Understanding Azure Durable Functions

In this post I would like to share a simple Azure Durable Function which will perform Simple Return Value along with some Timer Delays.

Function Replays

As you are aware Functions undergo multiple Replays which may require aligning your code as well. 

context.IsReplaying property says whether it is a replay.

The Code

The code ensures there is a 2 minute delay between sections.

namespace DurableFunctionTest
{
     public static class Function1
     {
         [FunctionName(“Function1_HttpStart”)]
         public static async Task<HttpResponseMessage> HttpStart(
             [HttpTrigger(AuthorizationLevel.Anonymous, “get”, “post”)]HttpRequestMessage req,
             [OrchestrationClient]DurableOrchestrationClient starter,
             ILogger log)
         {
             // Function input comes from the request content.
             string instanceId = await starter.StartNewAsync(“Function1”, null);

            log.LogInformation($”Started orchestration with ID = ‘{instanceId}’.”);

            return starter.CreateCheckStatusResponse(req, instanceId);
         }

        [FunctionName(“Function1”)]
         public static async Task<List<string>> RunOrchestrator(
             [OrchestrationTrigger] DurableOrchestrationContext context)
         {
             var outputs = new List<string>();

            outputs.Add(await context.CallActivityAsync<string>(“Function1_Hello”, “London”));

            return outputs;
         }

        [FunctionName(“Function1_Hello”)]
         public static string SayHello([ActivityTrigger] string name, ILogger log)
         {
             log.LogInformation($”step 1 {DateTime.Now.ToLongTimeString()}”);
             Thread.Sleep(2 * 60 * 1000); // 2min

            log.LogInformation($”step 2 {DateTime.Now.ToLongTimeString()}”);
            Thread.Sleep(2 * 60 * 1000); // 2min

            log.LogInformation($”step 3 {DateTime.Now.ToLongTimeString()}”);
             Thread.Sleep(2 * 60 * 1000); // 2min

            log.LogInformation($”step 4 {DateTime.Now.ToLongTimeString()}”);
             Thread.Sleep(2 * 60 * 1000); // 2min

            return $”Hello {name} !”;
         }
     }
}

The Output

2/10/2020 6:38:10 PM] 352ff6a310684f6eba4274bb81a54220: Function ‘Function1_Hello (Activity)’ started. IsReplay: False. Input: (40 bytes). State: Started. HubName: DurableFunctionsHub. AppName: . SlotName: . ExtensionVersion: 1.8.2. SequenceNumber: 9.
[2/10/2020 6:38:10 PM] Executing ‘Function1_Hello’ (Reason=”, Id=7f616c57-f299-4f9c-91ec-75feaa180893)
[2/10/2020 6:38:10 PM] step 1 1:38:10 PM
[2/10/2020 6:38:13 PM] Host lock lease acquired by instance ID ‘000000000000000000000000FE3C5631’.
[2/10/2020 6:40:08 PM] step 2 1:40:08 PM
[2/10/2020 6:40:10 PM] step 2 1:40:10 PM
[2/10/2020 6:40:10 PM] step 2 1:40:10 PM
[2/10/2020 6:42:08 PM] step 3 1:42:08 PM
[2/10/2020 6:42:10 PM] step 3 1:42:10 PM
[2/10/2020 6:42:10 PM] step 3 1:42:10 PM
[2/10/2020 6:44:08 PM] step 4 1:44:08 PM
[2/10/2020 6:44:10 PM] step 4 1:44:10 PM
[2/10/2020 6:44:10 PM] step 4 1:44:10 PM
[2/10/2020 6:46:08 PM] Executed ‘Function1_Hello’ (Succeeded, Id=02c78620-a573-4ffa-9f62-0aac2333ceaf)

The Inference

As you can see, although the Function replayed multiple times, but the restart was not loosing any time, it was accurate enough to replay from the past exit point.

Notes

Break your code into multiple chunks

Ensure transactions are protecting the Atomicity.