Is there a way to schedule "Reminders" in Durable Entities of Azure Durable Functions?

1.1k views Asked by At

I am using Azure Durable Functions in a research project and I want to verify what the best way is to implement the concept of Timers/Reminders in Durable Entities.

In Service Fabric, it was possible for an Actor to schedule a 'durable timer' so that the framework would call a method on the Actor itself. I am looking for a similar concept.

Consider a Durable Entity that is created for every Device in my system. I want that every actor runs functionality on a scheduled basis, and schedules this on its own. (I want to avoid having an orchestration function that needs to schedule tasks for every device, and just have the entities running the tasks on their own).

Is this something that is allowed, possible or foreseen?

Hope this question is clear enough, but happy to provide more context, where needed.

1

There are 1 answers

10
Peter Bons On BEST ANSWER

From the docs:

To invoke an operation on an entity, specify the [....] Scheduled time, which is an optional parameter for specifying the delivery time of the operation. For example, an operation can be reliably scheduled to run several days in the future. So there is an option to schedule invocations of the entities

But, you want to schedule from within the Durable Entity. This is also possible by using Entity.Current.SignalEntity (docs). This method as an overload that accepts a DateTime which specifies the time at which to start the operation.

The code below will start incrementing a counter by using an http triggered function. After the initial start by the azure function the entity will schedule an operation every 5 seconds for itself.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp3
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            [DurableClient] IDurableEntityClient client,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            // Tell the Durable Entity to increase a counter
            await client.SignalEntityAsync<ICounter>("aKey", e => e.IncreaseCount(1));

            return new OkResult();
        }
    }

    public interface ICounter
    {
        void IncreaseCount(int amount);
    }

    [JsonObject(MemberSerialization.OptIn)]
    public class Counter : ICounter
    {
        private readonly ILogger _log;

        public Counter(ILogger<Counter> log)
        {
            _log = log;
        }

        [JsonProperty("value")]
        public int CurrentValue { get; set; }

        public void IncreaseCount(int amount)
        {
            this.CurrentValue += amount;

            if(this.CurrentValue) > 10
                 return;

            // Schedule a call to this entity to IncreaseCount after 5 seconds. 
            // Once the method is called, schedule it again to create the effect of a timer
            Entity.Current.SignalEntity<ICounter>(Entity.Current.EntityId, DateTime.Now.AddSeconds(5), e => e.IncreaseCount(1));
            _log.LogInformation(this.CurrentValue.ToString());
        }

        [FunctionName(nameof(Counter))]
        public static Task Run([EntityTrigger] IDurableEntityContext ctx)
        {
            return ctx.DispatchAsync<Counter>();
        }
    }
}

This is just a rough sample but the takeaway is the use of Entity.Current.SignalEntity to schedule work by the entity itself.