Henny Lee
Henny Lee

Reputation: 3052

Durable Function, delay not accurate in seconds

I'm trying to create a durable function with a delay of x seconds. Unfortunately, the bigger x is, the inaccuracy increases.

I'm using the example shown in the MS docs:

function.json:

{
  "bindings": [
    {
      "name": "context",
      "type": "orchestrationTrigger",
      "direction": "in"
    }
  ],
  "scriptFile": "../dist/function/index.js"
}
const deadline = moment.utc(context.df.currentUtcDateTime).add(60, 'seconds');
yield context.df.createTimer(deadline.toDate());
context.df.callActivity("SendBillingEvent");

If I add 60 seconds to the timer, there's an extra delay of ~20 seconds. Are durable function inherently just inaccurate or is there another way to activate a function using a delay?


the logs shows:

[2021-02-20T09:23:03.878Z] the timer is: n {
[2021-02-20T09:23:03.878Z]   isCompleted: true,
[2021-02-20T09:23:03.878Z]   isFaulted: false,
[2021-02-20T09:23:03.878Z]   action: {
[2021-02-20T09:23:03.878Z]     fireAt: 2021-02-20T09:22:43.503Z,
[2021-02-20T09:23:03.878Z]     isCanceled: false,
[2021-02-20T09:23:03.878Z]     actionType: 5
[2021-02-20T09:23:03.879Z]   },
[2021-02-20T09:23:03.879Z]   result: undefined,
[2021-02-20T09:23:03.879Z]   timestamp: '2021-02-20T09:21:43.662554Z',
[2021-02-20T09:23:03.879Z]   id: 0,
[2021-02-20T09:23:03.879Z]   exception: undefined,
[2021-02-20T09:23:03.879Z]   completionIndex: 5,
[2021-02-20T09:23:03.879Z]   wasYielded: false
[2021-02-20T09:23:03.879Z] }

Upvotes: 1

Views: 869

Answers (1)

juunas
juunas

Reputation: 58743

I think it is inaccurate because of the way timers are created. When using the standard Azure Storage durability provider, a scheduled message on a Storage queue is used. Essentially DF adds a message to the queue that is scheduled to become visible at the time you set.

The instance running the orchestrator checks for new messages periodically by polling the queue. So there is most likely a delay between when the message becomes visible and the next message polling request. Then when it receives the message, DF has to load the instance history from the history table and then execute the orchestrator again. This also adds some overhead.

The Durable Task framework that DF uses does allow different durability providers to be used. Some of those might offer much more precise timers. But as far as I know, you can't configure DF to use a different one.

You can also try adjusting the polling frequency for messages: https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-perf-and-scale#queue-polling. Specifically, there is a maxQueuePollingInterval property in host.json that defaults to 00:00:30 (30 seconds). So when DF checks the queue and sees there are no messages, it increases the next polling time until it reaches the max set here. Check the host.json docs here to see where to set the property: https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-bindings#host-json.

Upvotes: 3

Related Questions