All Articles

Azure Durable Function

Functions

Traditional functions have below traits:

  • Re-usable
  • Responsible for single things and thus short-lived
  • Stateless: doesn’t hold any persistent state
    and don’t rely on the state
  • Event-driven
  • Scalable: when the usage spikes it will automatically cover it

As good as it sounds, there are couple of disadvantages to how traditional functions works.

  • Managing sequence: Changing events are hard to do in normal serverless functions. Therefore, handling error is difficult. e.g. What happens if step 3 fails. How do we know which step we are in and how can we handle that error.
  • Fanning out and fanning in: How to handle the next situation after the fan out and fan in… as in how to pull parallelsied computes into asingle one after it becomes distributed.
  • External event: What if we are waiting for external events to finish. We can use durable function to make it wait.
  • Long-running events: If function requires to watch for an event for a long time, traditional function won’t work.
  • Long-running http-based async/apis: We can’t open the connection for a long time. It’s important to know when the response is ready and in order to do this, we need to track the state.
  • Human interaction: In case when we need an approval or input from human, how do we co-relate this between events.

With durable function, we can overcome these disadvantages by maintaining local state and orchestrating multiple functions using orchestrator.

A tiny example of what it can do. We can effectively paralelise the work. If we are generating a report, for each order, I can call the shipping api but this each call to the shipping API would take some time

Durable functions

Now let’s have a look at the components of the durable functions!

Starter function

Starts orchestration or triggers the process (e.g. report, create an order) and sends the message to the orchestrator. Often a http endpoint.

Orchestrator function

This function coordinates activities and is the heart of the durable function. It also does status management.

Activity function

This is the function that will actually perform the work.

How it all works

Firstly, starter function gets the request and calls the orchestrator function. Then, execution history tracks the history in the history table. e.g. 1. Orchestrator started, 2. Execution started.

Instead of calling activity function directly, it goes to execution history log and asks, ‘hey, did we peform this activity function?‘. If not, orchestrator function starts the activity function. This also gets recorded in the history table and then, the orchestration completes. Our activity function wakes up and then looks at the history table and finds that it has to run the function. After activity function finishes running, it updates the execution history. e.g. Task completed

Replayability

One of the cool thing about durable function is that it remembers the state. When the orchestration function gets called again the second time, it asks the execution history, ‘Have I run the activity function?’ and the execution history will say ‘Yes’ and return the output from the first call.

Orchestrator Constraints

Replayability means that the orchestrator code must be deterministic. What that means is that the orchestrator function will be replayed multiple times but it must produce the same result each time.

For example, if you use Guid.NewGuid everytime the orchestrator function runs, it’s going to generate differrent result each time. Use something like DurableOrchestrationContext.CurrentUtcTime

You can also use activity function in order to keep orchestrator function deterministic. e.g. Do I/O in activity function.

One last thing, don’t write infinite loop! As we’ve learnt from above, , history logs will record everything and the inifite loops will cause memory to run out. Use DurableOrchestrationContext.ContinueAsNew to clean all the logs.

Published Jan 24, 2022

Interested in C# .NET DevOps anything backend