5

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 2

3

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==
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the detailed comment! It helped me progress. Would also just add that I DurableTaskClient.GetInstanceAsync has a getInputsAndOutputs parameter that helped me too.
0

You need to get the instance first, with the orchestration Id. Then you can get status.

OrchestrationRuntimeStatus? status = (await starter.GetInstanceAsync(orchestrationId))?.RuntimeStatus;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.