Azure Durable Entities Revisited
Azure Durable Entities have been around for a while, initially there was some good fan fare but it’s probably fair to say that there hasn’t been wide spread adoption of the technology. This could be because the virtual actor concept is unfamiliar to the traditional C# / Dotnet approach to solving software problems, or it could be that we don’t often find problem spaces that are best solved in this particular way.
In this post I’m going to give a brief overview of what Azure Durable Entities are and provide an example of how they can be used.
What are Durable Entities and when are they useful?
Durable Entities are part of the durable task framework that ships as part of Azure Functions, using the framework you can define classes that represent stateful objects, and in particular serverless entities that will run in the context of an Azure Function. Because they are stateful they can be useful for managing and persisting state across long-running processes - something that a typical Azure Function doesn’t do (since they aren’t stateful, they just run and then finish).
At DrDoctor most of our communication happens on Slack, years ago our main engineering channel was littered with messages from devs either letting everyone know they were using a cloud dev-test environment or asking what was free to be used and when they were done they would send another message to say they were finished.
Dev1: @nerds I’m using UAT 1
Dev2: @nerds are any UATs free?
Dev3: I’m still using UAT 2
Dev1: Finished using UAT 1
All these messages were really distracting.
Introducing /uat
- Slack and Durable Entities
I spent an evening learning how to build a custom Slash command for Slack, then a couple more evenings throwing together a simple Azure Function which used Durable Entities to represent our dev-test environments and our developers.
After a few evenings of tinkering with durable entities I started to get the hang of how they worked. My goal was to build a custom slash command for Slack that would call out to an Azure Function, the Azure Function would use Durable Entities to represent 1) our dev-test environments and 2) the developers.
Developers would be able to do the following from the custom slash command:
- Be able to claim an environment
- Be able to release an environment (if they are using it)
- Be able to see who is using what
To claim an environment developers can send /uat claim uat[n]
or release an environment by sending /uat release uat[n]
A developer can also see a list of all the environments by sending /uat list
A look at the DevTestResourceEntity
The full feature set of what our /uat
tool does now goes beyond the above simple requirements so instead of going into all the details I’m going to provide a simple overview of the entities and how they work.
The following snippet shows the DevTestResourceEntity
|
|
The first thing you’ll probably notice is the interface IDevTestResourceEntity
- this has very deliberately been added, you will see shortly the benefit we gain from this interface. The other thing to note is the Run
method, this is the boiler plate code that indicates to the Function runtime that this is an Entity
, and is also the code that is executed each time an entity is signalled.
Working with Entities
Entities communicate via messages or signals - the Functions framework/runtime provides a few different interfaces which can be injected into your normal functions which provide a mechanism to send a message to an entity or read the current state. Entities can also signal other entities.
Claiming a resource
|
|
The ClaimResource
function does a couple of things, the first is that it reads the current state of the entity (using the ReadEntityStateAsync
method), to do this an EntityId is passed in. A user can only claim a resource that exists or is unavailable, so if either of these conditions are met then an appropriate error message is sent back, otherwise IDurableEntityClient
interface is used to send a signal to the entity that it should execute the Claim
method. You can see this on line 28 above - and this is where having the strongly typed interface comes in handy, having the interface means strongly typed execution and reduces the likelihood of runtime errors since we’ll get compiler errors if a parameter of type is incorrect. This is also the recommended approach.
When working with Durable Entities, there are two methods of communication: one-way and two-way communication. In the above example, when using SignalEntityAsync
this is an example of one-way communication, the Claim
method return type Task
but even if I attempted to return a Task<string>
or something else the result will always be null.
Two-way communication is possible using IDurableOrchestrationContext
, in this case it would look something like this
|
|
More details on how this works and other access patterns can be found on Microsoft Learn - Developer’s guide to durable entities in .NET .
Releasing a resource
|
|
Much like the above ClaimResource
function the ReleaseResource
function works in much the same way, it checks a few things (whether the resource is being used and who it’s being used by, after all it wouldn’t be fair to release a resource being used by someone else 😀) and then signals the entity to execute the Release
method.
Listing all resources
|
|
Listing all resources is also relatively straightforward using the ListEntitiesAsync
method on IDurableEntityClient
, you will need to supply a PageSize
and then implement a looping mechanism if the number of entities is going to exceed the page size.
Making the most of Azure Serverless
The above two sections show the basic interactions with Durable Entities but there are some other really nifty things that can be done with Durable Entities and other Serverless offerings from Azure.
SignalR for real-time updates
SignalR is great for building web apps that need real-time updating capabilities, and with the serverless offering from Azure it’s really easy to integrate with Azure Functions. One of the things I put together was a real-time dashboard which shows who is using what resources.
My design skills clearly leave something to be desired.
Integrating this into the Durable Entities is surprisingly easy. As mentioned above the Run
method defined in the DevTestResourceEntity
serves as the entry point for the entity when executing. When this method is invoked the Azure framework injects the IDurableEntityContext
, but it can also be used to inject anything that is registered with the dependency injection framework.
We could change the above definition to the following
|
|
This will result in an IAsyncCollector
being injected during execution, the constructor will also need to be updated
|
|
This will then allow our entity to broadcast status updates to SignalR during execution, so for example the Claim
and Release
method could be updated with the following
|
|
Now whenever a resource is claimed or released the entity will broadcast an update to the resourcestatus
hub, which the web app subscribes to and when updates are broadcast the webpage will update the appropriate element to indicate the resource is either in use or available.
Azure Storage Queues
One of the other features that I implemented soon after getting the Slack app live was a reminder feature - after a resource had been claimed for 2 hours I wanted a message to go to the developer in Slack and ask if they were still using the resource (so they could release it if they no longer needed it). To do this I made use of Azure Storage Queues and schedule messages.
Publishing to a Storage queue from a Durable Entity is as simple as using SignalR, first the Run
method is updated
|
|
and the constructor
|
|
The Claim
method can then be updated to make use of the _reminderQueue
|
|
This will put a message into the reminders queue, scheduled for 2 hours time. I then implemented an Azure Function with a Storage Queue trigger which did the following:
- Looked up the entity
- Checked it was still claimed by that user
- If it was claimed by the same user it would send them a message on Slack asking if they were still using it
Wrapping up 🎁
I hope you’ve enjoyed this article on Azure Durable Entities, if you’ve not had a chance to play with them before I would encourage you to start looking out for places where this pattern could be useful and give them a try.
There’s lots of content I’ve not covered here, the Microsoft Learn docs are an absolute gold mine, and go into a lot of the details I’ve brushed over or completely skipped in this article:
🍪 I use Disqus for comments
Because Disqus requires cookies this site doesn't automatically load comments.
I don't mind about cookies - Show me the comments from now on (and set a cookie to remember my preference)