skip to Main Content

We are using Durable Functions in an Azure Function App as a backend. The frontend is hosted using Azure Static Web App and the API is linked so all the requests are proxied through the SWA. As a result it is hard to use the built-in status-query route (runtime/webhooks/durabletask/instances) as it isn’t exposed in SWA (maybe there is a way to do that?) so in the past we would have our own custom Function to get the status:

[FunctionName("GetStatus")]
public async Task<DurableOrchestrationStatus> GetStatus([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "status/{instanceId}")] HttpRequest req, [DurableClient] IDurableOrchestrationClient client, string instanceId)
{
    return await client.GetStatusAsync(instanceId);
}

This is fine as the DurableOrchestrationStatus contains the information we need such as the output property to see potential errors. However after migrating to Isolated Process the interface has changed and it seems that we can only now use DurableTaskClient.GetInstanceAsync which returns OrchestrationMetadata however that doesn’t appear to contain the same info as DurableOrchestrationStatus. It seems that the intended way is to call the runtime/webhooks/durabletask/instances endpoint but I was hoping there was a way to access the same info so we can expose it through the SWA.

2

Answers


  1. Yes, There are some Public API changes when you migrate to Isolated Functions, Refer this Table to get the correct method to get the Status of Azure Durable Functions isolated.

    If you intend to expose orchestration status information through your Azure Static Web App (SWA) and find that the proxying of requests complicates the use of the built-in status-query route, one possible solution is to create a custom HTTP-triggered function. The DurableTaskClient provides the GetStatusAsync method. However, it returns OrchestrationInstance and OrchestrationRuntimeStatus, which may lack some of the detailed information found in the original DurableOrchestrationStatus.

    Sample code that you can use:-

    using Microsoft.AspNetCore.Http;
    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.Azure.WebJobs.Extensions.DurableTask;
    using Microsoft.DurableTask;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Threading.Tasks;
    
    namespace FunctionApp2
    {
        public static class Function1
        {
            [Function(nameof(Function1))]
            public static async Task<List<string>> RunOrchestrator(
                [Microsoft.Azure.Functions.Worker.OrchestrationTrigger] TaskOrchestrationContext context)
            {
                ILogger logger = context.CreateReplaySafeLogger(nameof(Function1));
                logger.LogInformation("Saying hello.");
                var outputs = new List<string>();
    
                outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo"));
                outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Seattle"));
                outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "London"));
    
                return outputs;
            }
    
            [Function(nameof(SayHello))]
            public static string SayHello([Microsoft.Azure.Functions.Worker.ActivityTrigger] string name, FunctionContext executionContext)
            {
                ILogger logger = executionContext.GetLogger("SayHello");
                logger.LogInformation("Saying hello to {name}.", name);
                return $"Hello {name}!";
            }
    
            [Function("Function1_HttpStart")]
            public static async Task<HttpResponseData> HttpStart(
                [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req,
                [Microsoft.Azure.Functions.Worker.DurableClient] IDurableOrchestrationClient client,
                FunctionContext executionContext)
            {
                ILogger logger = executionContext.GetLogger("Function1_HttpStart");
                string instanceId = await client.StartNewAsync(nameof(Function1), instanceId: null);
    
                logger.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId);
    
                return (HttpResponseData)client.CreateCheckStatusResponse(req, instanceId);
            }
    
            [Function("GetStatus")]
            public static async Task<HttpResponseData> GetStatus(
                [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "status/{instanceId}")] HttpRequestData req,
                [Microsoft.Azure.Functions.Worker.DurableClient] IDurableOrchestrationClient client,
                string instanceId,
                FunctionContext executionContext)
            {
                var logger = executionContext.GetLogger("GetStatus");
    
                try
                {
                    var status = await client.GetStatusAsync(instanceId);
                    if (status == null)
                    {
                        return req.CreateResponse(HttpStatusCode.NotFound);
                    }
    
                    var response = req.CreateResponse(HttpStatusCode.OK);
                    await response.WriteAsJsonAsync(status);
                    return response;
                }
                catch (Exception ex)
                {
                    logger.LogError($"Error getting status for instance {instanceId}: {ex.Message}");
                    return req.CreateResponse(HttpStatusCode.InternalServerError);
                }
            }
        }
    }
    

    Also, When I created a Default Durable .Net Isolated Function and ran Http_start function, I received the Get status URI which you can call in your SWA by linking it with the Azure Functions, Refer below:-

    https://valleyfuncisolated.azurewebsites.net/api/Function1_HttpStart
    

    enter image description here

    statusQueryGetUri:-

    https://valleyfuncisolated.azurewebsites.net/runtime/webhooks/durabletask/instances/xxxxxxx5cb?code=xxxxxxxhYv144mAzFuC3De1Q==
    

    enter image description here

    Refer my SO answer to link the Function with SWA and call it with the URL below:-

    enter image description here

    URL:-

    https://staticappurlxxxxge-coast-xxxx03.4.azurestaticapps.net/runtime/webhooks/durabletask/instances/e9233969c9f943a1ae6bf7f1d4deb5cb?code=xxxxxx1Q==
    
    Login or Signup to reply.
  2. How do you solve the problem with CreateCheckStatusResponse being synchronous and the method failing with ‘Synchronous operations are disallowed.’

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search