2
[FunctionName("SetDurable")]
public static async Task<HttpResponseMessage> SetDurable(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = "SetDurable/{durable}")] HttpRequestMessage req,
        [DurableClient] IDurableEntityClient client,
        string durable)
        {
           var entityId = new EntityId(DurableEntitiesNames.BirSessionIdentificatorEntity, DurableEntitiesNames.BirSessionIdentificatorKey);
           await client.SignalEntityAsync<IBirSessionIdentificator>(entityId, identificator => identificator.Set(durable) );
           //await Task.Delay(2000);
           EntityStateResponse<JObject> stateResponse = await client.ReadEntityStateAsync<JObject>(entityId);
           var setResult = stateResponse.EntityState.ToObject<BirSessionIdentificatorResult>().Sid;
           return new HttpResponseMessage(HttpStatusCode.OK){Content = new StringContent($"{setResult}")};
    }
    

In Azure Functions v3 when i try to set the value of durable entity and then immediately try to read this value, it returns old value instead of the new value. But when i uncomment the Task.Delay and make it wait 2 seconds after setting the value of durable entity i get correct value while trying to read it.

Is there any way to await the completion of durable entity value setting operation?

  • Hi, just checking, did my answer help you out? If so, please [mark it as answer](https://stackoverflow.com/help/someone-answers) or feel free to ask for clarification. – Peter Bons Oct 22 '20 at 13:56

1 Answers1

2

Is there any way to await the completion of durable entity value setting operation?

No, at least not when using SignalEntityAsync. See the docs:

It's important to understand that the "signals" sent from the client are simply enqueued, to be processed asynchronously at a later time. In particular, the SignalEntityAsync usually returns before the entity even starts the operation, and it is not possible to get back the return value or observe exceptions. If stronger guarantees are required (e.g. for workflows), orchestrator functions should be used, which can wait for entity operations to complete, and can process return values and observe exceptions.

The bold part is your way out: you can use a proxy from within an orchestration to get access to the durable entity. That way you can await the operation. An example:

[FunctionName("DeleteCounter")]
public static async Task<HttpResponseMessage> DeleteCounter(
    [HttpTrigger(AuthorizationLevel.Function, "delete", Route = "Counter/{entityKey}")] HttpRequestMessage req,
    [DurableClient] IDurableEntityClient client,
    string entityKey)
{
    var entityId = new EntityId("Counter", entityKey);
    await client.SignalEntityAsync<ICounter>(entityId, proxy => proxy.Delete());    
    return req.CreateResponse(HttpStatusCode.Accepted);
}

here we await the call of the Delete method on the entity.

Peter Bons
  • 26,826
  • 4
  • 50
  • 74
  • Either I'm reading the [docs](https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.webjobs.extensions.durabletask.idurableentityclient.signalentityasync?view=azure-dotnet#microsoft-azure-webjobs-extensions-durabletask-idurableentityclient-signalentityasync-1(microsoft-azure-webjobs-extensions-durabletask-entityid-system-action((-0)))) wrong. But it clearly states that `SignalEntityAsync` returns *A task that completes when the message has been reliably enqueued.* – smoksnes Jun 09 '22 at 09:38
  • @smoksnes indeed the operation is *enqueued*, not *executed* or *completed*. That state is reached once the operation is dequeued and actually performed. – Peter Bons Jun 09 '22 at 11:38
  • @smoksnes as stated in my answer: *It's important to understand that the "signals" sent from the client are simply enqueued, **to be processed asynchronously at a later time**. * – Peter Bons Jun 09 '22 at 11:40
  • Well, yes, I totally agree. That part i correct. However I suggest you change *That way you can await the operation* to something like *That way you can await the operation to be queued*. And similarly *here we await the call of the Delete method on the entity* to *here we await the Delete method to be queued*. – smoksnes Jun 09 '22 at 11:45
  • Otherwise you should use `CallEntityAsync` - *Calls an operation on an entity and waits for it to complete* - [docs](https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.webjobs.extensions.durabletask.idurableorchestrationcontext.callentityasync?view=azure-dotnet) - that way you actually await the operation, which `SignalEntityAsync` doesn't. Then you will need a `IDurableOrchestrationContext` instead of `IDurableEntityClient ` – smoksnes Jun 09 '22 at 11:47