Azure Durable Functions have support for different patterns, which enable us to build serverless and stateful applications without worrying about the state management implementation details. One of these useful patterns is the Asynchronous Http APIs. This pattern comes in handy when client applications need to trigger long running processes exposed as APIs and do something else after a status is reached. You might be thinking that the best way to implement an async API is by enabling the API to raise an event once it finishes so the client can react to it. For instance via a webhook (Http callback request), an Event Grid event, or even using SignalR. That is true, however, in many cases, client apps cannot be modified, or there are security or networking restrictions which make polling the best or the only feasible alternative. In this post, I’ll describe how to implement the Asynchronous Http API pattern on Durable Functions based on the polling client approach.
Before we get into the details, it’s worth noting that this pattern can be used to implement a custom trigger or action for Logic Apps with the polling pattern.
To demonstrate how to implement this pattern, I’ll use the scenario of “Call for Speakers” in a conference. In this, potential speakers submit a topic through an app, and they are very keen to know as soon as possible if they have been selected to present. Of course, in a real scenario there will be timelines and speakers would be notified before the agenda is published, so they wouldn’t need to keep continuously asking for the status of their submission. But I believe you get the idea that this is being used for illustration purposes only ;)
The solution is based on Azure Durable Functions’ building blocks, including orchestration clients, the orchestration function, and activity functions. I’ve used dummy activity functions, as the main purpose of this post is to demonstrate the capabilities to implement an Asynchronous Http API. In case you want to understand how to implement this further, you can have a look at my previous posts on how to implement approval workflows on Durable Functions.
The diagram below shows the different components of the solution. As you can see, there is a client app which submits the application by calling the
Submit Azure function, and then can get the status of the application by calling a GET
Status Azure function. The orchestration function controls the process and calls the activity functions.
The main components of the solution are described below. The comments in the code should also help you to better understand each of them. You can find the full solution sample code here.
Http triggered function which implements the
DurableOrchestrationClient. This function receives a “Call-for-Speakers” submission as a POST with a JSON payload as the request body. Then, it starts the submission processing orchestration. Finally, it returns to the client the URL to the endpoint to get the status using the
retry-after http headers.
Process Submission Function
Orchestration function which implements the function chaining pattern for each of the stages of the submission approval process. It’s also in charge of updating the custom status of the instance as it progresses.
Get Status Function
This is an Http function that allows clients to get the status of an instance of a Durable Function orchestration. You can get more details of this implementation here.
In many of the samples, they explain you how to use the
CreateCheckStatusResponse method to generate the response to the client. However, make sure that that you fully understand what this returns. Given that the returned payload includes management endpoints with their corresponding keys, by providing that, you would allow the clients not only to get the status of a running instance, but also to 1) get the activity execution history, 2) get the outputs of the already executed activity functions, 3) send external events to the orchestration instance, and 4) terminate that instance. If you don’t want to give those privileges to the clients, you need to expose an http function that returns only the minimum information required. In this wrapper function, you could also enrich the response if need be. If you only need to send the status back, I would recommend you to use the
GetStatusAsync method instead.
The sample function below makes use of the
GetStatusAsync method of the orchestration client, and leverages the
retry-after Http headers.
In this post, I’ve shown how to implement Asynchronous Http APIs using Durable Functions with the polling consumer pattern. I’ve also explain the differences between using
GetStatusAsync methods. The former prepares a response which expose different management endpoints with a key that allow clients to do much more than just getting the status, while the latter just returns the instance status. I hope you’ve enjoyed and found useful this post.
If you are interested in more posts about patterns on Durable Functions, you can also check out:
- Azure Durable Functions Pattern: Approval Workflow with SendGrid
- Azure Durable Functions Pattern: Approval Workflow with Slack
Cross-posted on Paco’s Blog.
Follow Paco on @pacodelacruz.