Search code examples
azurepowershellazure-functionsazure-web-app-service

Azure function app with http trigger to return a message but continue working on some more tasks


I have an Azure function in powershell with an http trigger as backend and a web App in ASP.NET as front end. The front end will send a get message to the back end and triggers to start the Azure function. I want to immediately return a text message from the function app back to the front end so the user knows he started the process and let him close the browser, I don't want the user to wait for anything else, and then the back end continues working on some tasks that would take a couple of more minutes. I have tried a few ways and the only way that it works is to terminate the function app early.

This returns the message but I have to have a return statement after which terminates the function early.

# Function app starts
.
.
.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
            StatusCode = [HttpStatusCode]::OK
            Body = $messageOutput
        })

# Function app continues
.
.

I looked at the Orchestrator and it seems to be an overkill for what I want to do. Even if I choose the orchestrator model I am not sure which of the five model (Function chaining,Fan-out/fan-in,Async HTTP APIs,Monitoring,Human interaction,Aggregator (stateful entities)) would that be and how to achieve what I want to do here.

The Azure Web App passes two parameters using Get command to the httpTrigger(ed) function app. I also need to have that as a requirement.


Solution

  • Yes, you can use the Durable Functions orchestration pattern called "Async HTTP APIs" for your requirement.

    This pattern is useful for scenarios where the client application needs to perform other tasks while waiting for the orchestration to complete or to run function in background in orchestration after Http response message.

    For reference check this document.

    Default sample of Durable Function is created in same pattern.

    For reference check this document.

    To create durable function you need to create three functions Http starter, Orchestrator and activity.

    #Directory :

    Powershell/
    │
    ├── DurableFunctionsHttpStart1/
    │   ├──function.json
    │   └── run.ps1
    │
    ├── DurableFunctionsOrchestrator1/
    │   ├──function.json
    │   └── run.ps1
    │
    ├── Hello1/
    │   ├──function.json
    │   └── run.ps1
    │
    ├── host.json
    ├── local.settings.json
    ├── profile.ps1
    └── requirements.psd1
    

    I am using Sample Durable function which call same activity function 3 times with different input value. I have added a simple sum of two numbers and printing its value.

    Note : not necessary to call activity 3 times.

    In Http Starter you get url to get status query of the running orchestration with output message of activity function by default.

    To get custom message with the urls use this.

    DurableFunctionsHttpStart1/run.ps1:

    using namespace System.Net
    
    param($Request, $TriggerMetadata)
    
    $FunctionName = $Request.Params.FunctionName
    $InstanceId = Start-DurableOrchestration -FunctionName $FunctionName
    $Message = "Your Process is running in the background"
    Write-Host "Started orchestration with ID = '$InstanceId'"
    
    $Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId
    $ResponseBody = @{
        Message = $Message
        Response = $Response
    }| 
    
    $HttpResponse = [HttpResponseContext]@{
        StatusCode = [HttpStatusCode]::OK
        Body = $ResponseBody
    }
    Push-OutputBinding -Name Response -Value $HttpResponse
    

    DurableFunctionsHttpStart1/function.json:

    {
      "bindings": [
        {
          "authLevel": "anonymous",
          "name": "Request",
          "type": "httpTrigger",
          "direction": "in",
          "route": "orchestrators/{FunctionName}",
          "methods": [
            "get"
          ]
        },
        {
          "type": "http",
          "direction": "out",
          "name": "Response"
        },
        {
          "name": "starter",
          "type": "durableClient",
          "direction": "in"
        }
      ]
    }
    

    DurableFunctionsOrchestrator1/run.ps1:

    param($Context)
    
    $output = @()
    
    $output += Invoke-DurableActivity -FunctionName 'Hello1' -Input 'Tokyo'
    $output += Invoke-DurableActivity -FunctionName 'Hello1' -Input 'Seattle'
    $output += Invoke-DurableActivity -FunctionName 'Hello1' -Input 'London'
    
    $output
    
    

    DurableFunctionsOrchestrator1/function.json:

    {
      "bindings": [
        {
          "name": "Context",
          "type": "orchestrationTrigger",
          "direction": "in"
        }
      ]
    }
    

    Hello1/run.ps1:

    param($name)
    $sum = 4 + 5
    "Hello $name!`n $sum"
    

    Hello1/function.json:

    {
      "bindings": [
        {
          "name": "name",
          "type": "activityTrigger",
          "direction": "in"
        }
      ]
    }
    

    OUTPUT

    using Name DurableFunctionsOrchestrator1 in place of {FunctionName} in url to run orchectrationTrigger.

    to get the Status of your function open statusQueryGetUri url.

    {
        "name": "DurableFunctionsOrchestrator1",
        "instanceId": "bc5fe8e4-245d-4418-b758-72fb9ad8cd29",
        "runtimeStatus": "Completed",
        "input": null,
        "customStatus": null,
        "output": [
            "Hello Tokyo!\n 9",
            "Hello Seattle!\n 9",
            "Hello London!\n 9"
        ],
        "createdTime": "2024-02-29T06:39:06Z",
        "lastUpdatedTime": "2024-02-29T06:39:07Z"
    }