Search code examples
azureazure-functions

Isolated Azure Durable Entity Function never executes


I have created a .net 8 isolated function app as a POC for using durable entities containing a single entity. Also created 2 endpoints, one to retrieve the entity value, the other to act on the entity. When retrieving the value of the entity it is always null. I have left the app running overnight to see if it is a timing issue and the value is still returned as null. I have tried this both running on Azureite as well a storage account in Azure.

The entity function is recognized by the framework but a breakpoint inside the function is never hit.

The code below is scraped directly from the MS documentation on Durable Entities. here

Entity Definition:

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

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

     public void Add(int amount)
     {
         this.State += amount;
     }

     public Task Reset()
     {
         this.State = 0;
         return Task.CompletedTask;
     }

     public Task<int> Get()
     {
         return Task.FromResult(this.State);
     }

     // Delete is implicitly defined when defining an entity this way

     [Function(nameof(Counter))]
     public static Task Run([EntityTrigger] TaskEntityDispatcher dispatcher)
         => dispatcher.DispatchAsync<Counter>();
 }

Function Definitions:

 [Function("GetCounter")]
 public static async Task<HttpResponseData> GetCounter(
     [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Counter/{entityKey}")] HttpRequestData req,
     [DurableClient] DurableTaskClient client, string entityKey)
 {
     var entityId = new EntityInstanceId("Counter", entityKey);
     EntityMetadata<int>? entity = await client.Entities.GetEntityAsync<int>(entityId);
     HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
     await response.WriteAsJsonAsync(entity?.State);

     return response;
 }


 [Function("AddCounter")]
 public static async Task<HttpResponseData> AddCounter(
     [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Counter/{entityKey}/add")] HttpRequestData req,
     [DurableClient] DurableTaskClient client, string entityKey)
 {
     var entityId = new EntityInstanceId("Counter", entityKey);
     await client.Entities.SignalEntityAsync(entityId, "add", 1);
     
     HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
     

     return response;
 }

Recognized Functions

csproj file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.3" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.0" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
  </ItemGroup>
</Project>

Solution

  • Your code worked fine for me. As I mentioned in comment and I am using DurableTask Version 1.1.1.

    I tried using 1.1.3 was also facing the similar issue. It is becuase of package support with other packages.

    I tried upgrading the other packages also but all throw some error. Packages are not compatible with each other.

    I would suggest using 1.1.1 or 1.1.2, with these versions of other packages.

    This Worked for me.

    Function.cs:

    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.DurableTask;
    using Microsoft.DurableTask.Client;
    using Microsoft.DurableTask.Client.Entities;
    using Microsoft.DurableTask.Entities;
    using Microsoft.Extensions.Logging;
    using System.Net;
    
    namespace FunctionApp9
    {
        public static class Function1
        {
            [Function("GetCounter")]
            public static async Task<HttpResponseData> GetCounter(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Counter/{entityKey}")] HttpRequestData req,
        [DurableClient] DurableTaskClient client, string entityKey)
            {
                var entityId = new EntityInstanceId("Counter", entityKey);
                EntityMetadata<int>? entity = await client.Entities.GetEntityAsync<int>(entityId);
                HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
                await response.WriteAsJsonAsync(entity?.State);
    
                return response;
            }
    
    
            [Function("AddCounter")]
            public static async Task<HttpResponseData> AddCounter(
                [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Counter/{entityKey}/add")] HttpRequestData req,
                [DurableClient] DurableTaskClient client, string entityKey)
            {
                var entityId = new EntityInstanceId("Counter", entityKey);
                await client.Entities.SignalEntityAsync(entityId, "add", 1);
    
                HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
    
    
                return response;
            }
    
        }
        public class Counter : TaskEntity<int>
        {
            readonly ILogger logger;
    
            public Counter(ILogger<Counter> logger)
            {
                this.logger = logger;
            }
    
            public void Add(int amount)
            {
                this.State += amount;
            }
    
            public Task Reset()
            {
                this.State = 0;
                return Task.CompletedTask;
            }
    
            public Task<int> Get()
            {
                return Task.FromResult(this.State);
            }
    
            // Delete is implicitly defined when defining an entity this way
    
            [Function(nameof(Counter))]
            public static Task Run([EntityTrigger] TaskEntityDispatcher dispatcher)
                => dispatcher.DispatchAsync<Counter>();
        }
    }
    
    

    FunctionApp9.csproj:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <AzureFunctionsVersion>v4</AzureFunctionsVersion>
        <OutputType>Exe</OutputType>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>
      <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.2" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
        <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
      </ItemGroup>
      <ItemGroup>
        <None Update="host.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="local.settings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
          <CopyToPublishDirectory>Never</CopyToPublishDirectory>
        </None>
      </ItemGroup>
      <ItemGroup>
        <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
      </ItemGroup>
    </Project>
    

    OUTPUT: