.NET Isolated Azure Durable Functions: Support for Durable Entities with Netherite Storage Provider

Finally, Durable Entities are now supported with Netherite Storage Provider in .NET Isolated Azure Durable Functions.

While durabletask-netherite: 1.5.1 says it added support for isolated entities, unfortunately, it does not work (microsoft/durabletask-netherite/issues/390: System.NotSupportedException: Durable entities are not supported by the current backend configuration). We need Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Netherite version 1.5.3 (at least) for this to work.

Now let’s look at how to configure Netherite Storage Provider in a .NET Isolated Azure Durable Function.

First, we need to install the following package: 
   Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Netherite >= 1.5.3

Then we need to update the host.json as follows.

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "storageProvider": {
        "type": "Netherite"
      }
    }
  },
  "logging": {
    ...
  }
}

And finally, for local development, we need to update the local.settings.json as follows.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "EventHubsConnection": "SingleHost",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  }
}

You need to set up an Event Hubs namespace to run Netherite on Azure and I am not covering that in this post.

Now let’s write a simple function to try out the Durable Entity functionality with Netherite.

I have the following simple CounterEntity.

using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask.Entities;
using Microsoft.Extensions.Logging;

namespace AzureFunctionsDemo.Netherite;

public class CounterEntity : TaskEntity<int>
{
    readonly ILogger logger;

    public CounterEntity(ILogger<CounterEntity> logger)
    {
        this.logger = logger;
    }

    public void Add(int amount) => State += amount;

    public void Reset() => State = 0;

    public int Get() => State;

    [Function(nameof(CounterEntity))]
    public Task RunEntityAsync([EntityTrigger] TaskEntityDispatcher dispatcher)
    {
        return dispatcher.DispatchAsync(this);
    }
}

And I am invoking CounterEntity through the following HTTP function that calls a Durable Function.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Entities;
using Microsoft.Extensions.Logging;

namespace AzureFunctionsDemo.Netherite;

public static class Function1
{
    [Function(nameof(HttpStart))]
    public static async Task<HttpResponseData> HttpStart(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
        [DurableClient] DurableTaskClient client,
        FunctionContext executionContext)
    {
        ILogger logger = executionContext.GetLogger(nameof(HttpStart));

        string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(EntityOrchestrator));

        logger.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId);

        return await client.CreateCheckStatusResponseAsync(req, instanceId);
    }

    [Function(nameof(EntityOrchestrator))]
    public static async Task<int> EntityOrchestrator(
        [OrchestrationTrigger] TaskOrchestrationContext context)
    {
        ILogger logger = context.CreateReplaySafeLogger(nameof(EntityOrchestrator));

        var entityId = new EntityInstanceId(nameof(CounterEntity), "myCounter");

        await context.Entities.CallEntityAsync(entityId, nameof(CounterEntity.Add), 10);

        int currentValue = await context.Entities.CallEntityAsync<int>(entityId, nameof(CounterEntity.Get));

        return currentValue;
    }
}

After triggering the HTTP function, it will execute the Orchestration invoking the Durable Entity. Once the Orchestration is completed and when I check the Orchestration Status, I can see the current value of the CounterEntity.

Orchestration Status

Great to see it’s working, was waiting for this. 

Hope this helps.More read:
Configure Durable Functions with the Netherite storage provider

Happy Coding.

Regards,

Jaliya

This blog is part of Microsoft Azure Week! Find more similar blogs on our Microsoft Azure Landing page here.

About the author:

Jaliya Udagedara, MVP

I am a software developer working on Microsoft technology stack most of the time. I have also worked on (sometimes still do) non-Microsoft technology stacks, but I prefer to be on Microsoft stack as much as possible.

I am a Microsoft MVP since 2014. My most proficient programming language is C#, I work with SQL/NoSQL databases and Microsoft Azure is my preferred Cloud provider. I do DevOps, mostly on Azure DevOps and GitHub. I like to be on the edge of the technologies and learn new things.

I like writing blog posts and I maintain my blog at https://jaliyaudagedara.blogspot.com/. It’s a good way to continuously improve and to share what I know/learn with the rest of the community. I also do speak in software development-related technical events.

Reference:

Udagedara, J. (2024) .NET Isolated Azure Durable Functions: Support for Durable Entities with Netherite Storage Provider. Available at: Jaliya’s Blog: .NET Isolated Azure Durable Functions: Support for Durable Entities with Netherite Storage Provider (jaliyaudagedara.blogspot.com) [Accessed on 24/06/2024]

Share this on...

Rate this Post:

Share: