In the movies, Thor keeps saying that he “is the strongest Avenger”. Some people say that it’s actually Hulk, but I guess it’s a matter of perspective. How can we find a solution to this riddle? By using Azure Durable Entities of course!

Azure Durable Functions have been a very nice addition to the Azure ecosystem. They basically let you write stateful functions and run them serverless. There’s as usual a whole plethora of patterns you can apply with them, like Function Chaining

or Fan out/Fan in

or Monitors

There’s a full list available in the official docs, make sure to take a look.

Durable Functions currently come in four different types: Activity, Orchestrator, Entity, and Client. I’ve done a bit of work with all of them and today I’m going to talk a bit about Entity Functions.

Entity Functions define operations for reading and updating small pieces of state, known as durable entities. They act as small tiny services that talk between each other via messages. Each entity has a unique id and an internal state. When triggered, they can update their state and/or send a message to other entities. Or do other things like calling external services, triggering orchestrations, and so on.

It is also very important to note that Entity Functions focus on reliability more than performance, by using reliable queues to handle messaging.

Entity Functions are basically another form of the Actor Model and share a lot of similarities with Project Orleans, although with some interesting differences.

To showcase how they work, I prepared a super-duper example, WhoIsTheStrongest 😀 It’s a distribute voting platform, aimed to decide who’s the strongest Avenger! The code is available on GitHub, feel free to wander around.

The UI is written in Blazor and to be fair, there’s nothing much to say. You can pick your favorite Avenger, click on the button and vote. The system will record your choice and after few seconds you’ll see the updated leaderboard.

The bulk of the logic is handled by Durable Entities: the first time an Avenger gets a vote, the system will generate an Id and spin up an Entity instance. The Entity state will hold the score and the last vote date. Azure will take care of the rest. The next time the score is incremented, the framework will instantiate the Entity, deserialize its state, and run the operation.

[JsonObject(MemberSerialization.OptIn)]
public class CharacterScore 
{
	[JsonProperty("score")]
	public int Score { get; private set; }

	[JsonProperty("lastIncrement ")]
	public DateTime LastIncrement { get; private set; }

	public void Increment()
	{
		this.Score++;
		this.LastIncrement = DateTime.UtcNow;
	}

	[FunctionName(nameof(CharacterScore))]
	public static Task Run([EntityTrigger] IDurableEntityContext ctx) => ctx.DispatchAsync<CharacterScore>();
}

Few things to note:

  • The Run function contains the boilerplate required for using the class-based syntax. It must be a static Azure Function. 
  • an Entity is a regular POCO class. Public callable operations must return a Task or void.
  • an Entity must be JSON-serializable

A full list of constraint is as usual available in the docs.

The score increment operation on an Entity can be triggered by a message in a Queue. The system also exposes an HTTP GET endpoint, returning the current leaderboard. Those are standard Azure Functions, which get an instance of IDurableEntityClient as input. This client is what allows them to interact and call operations on Entities.