DEV Community

Massimo Bonanni
Massimo Bonanni

Posted on

How to delete a Durable Entity

In this post I would like to show you how you can delete a Durable Entity in your solution.
Probably you don't know, but that functionality is built-in in the Durable Functions platform.
Suppose we have the definition of our entity (a counter):

public interface ICounter
{
    void Increment();
}
Enter fullscreen mode Exit fullscreen mode

and one implementation of our counter:

public class MyCounter : ICounter
{
    private readonly ILogger _logger;
    public MyCounter(ILogger logger)
    {
        _logger = logger;
    }

    public int Count { get; set; } = 0;

    public void Increment()
    {
        _logger.LogInformation($"Increment counter {Entity.Current.EntityKey}");
        Count++;
    }

    [FunctionName(nameof(MyCounter))]
    public static Task Run([EntityTrigger] IDurableEntityContext ctx, ILogger logger)
        => ctx.DispatchAsync<MyCounter>(logger);
}
Enter fullscreen mode Exit fullscreen mode

We can manage our counters using a simple client function like the following:

public class IncrementCounterClient
{
    private readonly ILogger _logger;

    public IncrementCounterClient(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<IncrementCounterClient>();
    }

    [FunctionName("IncrementCounter")]
    public async Task<IActionResult> Run(
       [HttpTrigger(AuthorizationLevel.Function, "get", Route = "counters/{counterName}")] HttpRequest req,
       string counterName,
       [DurableClient] IDurableEntityClient client)
    {
        _logger.LogInformation("IncrementCounter function");
        IActionResult responseData = null;

        var entityId = new EntityId(nameof(MyCounter), counterName);

        await client.SignalEntityAsync<ICounter>(entityId, entity => { entity.Increment(); });

        return responseData;
    }
}
Enter fullscreen mode Exit fullscreen mode

Using the API exposed by the previous client we can increment a counter with a simple Get request like the following:

curl http://localhost:7214/api/counters/counter01
Enter fullscreen mode Exit fullscreen mode

If you are testing your functions locally, you can see the traces in the Azure Functions debug console:

The Azure Functions console during the counter increment

The operation changes the status of the entity in memory, and then, into the local storage account and you can see it opening the Storage Explorer tool and look at the HubInstances table:

The entities history table in the local storage

If we open the row with partition key @mycounter@counter01, we can see the status of the entity (in the input column) and also we can have the information that the Entity exists in the column called CustomStatus:

The entity property values

Now, if we want to delete the entity, we can use the built-in delete operation.
The Durable Entities platform provides us with built-in APIs to manage entities. In particular, if we want to perform an operation of a particular entity (for example our Increment), we can use the following API:

POST /runtime/webhooks/durabletask/entities/{entityName}/{entityKey}
    ?op={operationName}
Enter fullscreen mode Exit fullscreen mode

In our scenario, entityName is mycounter, entityKey is counter01 and op is increment.

curl -X POST  http://localhost:7214/runtime/webhooks/durabletask/entities/mycounter/counter01?op=increment
Enter fullscreen mode Exit fullscreen mode

You can find more info about this features in the official documentation.
If we set op=delete (even if we didn't define the delete method in our entity interface), we have this result:

The entity property values after the delete

As we can see, the CustomStatus value is changed and the internal state of the entity is empty.
The entity row is still there, but for the platform the entity is deleted. If you try to retrieve the entity using the ListEntitiesAsync methods (of the IDurableEntityClient interface), you don't find the entity previously deleted.

If you define a delete method in your entity (you can implement it directly in the entities without define in the interface), that method will be called when you try to post the op=delete operation and you can manage the deletion by yourself (using, for example, the Entity.Current.DeleteState() method inside your entity).

Top comments (0)