Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use async helper functions in an Azure Durable Functions Orchestator?

I am trying to track down some occasional Non-Deterministic workflow detected: TaskScheduledEvent: 0 TaskScheduled ... errors in a durable function project of ours. It is infrequent (3 times in 10,000 or so instances).

When comparing the orchestrator code to the constraints documented here there is one pattern we use that I am not clear on. In an effort to make the orchestrator code more clean/readable we use some private async helper functions to make the actual CallActivityWithRetryAsync call, sometimes wrapped in an exception handler for logging, then the main orchestrator function awaits on this helper function.

Something like this simplified sample:

[FunctionName(Name)]
public static async Task RunPipelineAsync(
    [OrchestrationTrigger]
    DurableOrchestrationContextBase context,

    ILogger log)
{
    // other steps

    await WriteStatusAsync(context, "Started", log);

    // other steps

    await WriteStatusAsync(context, "Completed", log);
}

private static async Task WriteStatusAsync(
    DurableOrchestrationContextBase context,
    string status,
    ILogger log
)
{
    log.LogInformationOnce(context, "log message...");
    try
    {
        var request = new WriteAppDocumentStatusRequest 
        {
            //...
        };

        await context.CallActivityWithRetryAsync(
            "WriteAppStatus",
            RetryPolicy,
            request
        );
    }
    catch(Exception e)
    {
        // "optional step" will log errors but not take down the orchestrator
        // log here
    }
}

In reality these tasks are combined and used with Task.WhenAll. Is it valid to be calling these async functions despite the fact that they are not directly on the context?

like image 271
Gavin H Avatar asked Nov 15 '19 16:11

Gavin H


People also ask

Which type of Azure durable function should you use?

If you want to test an orchestrator or entity function in the Azure Portal, you must instead run a client function that starts an orchestrator or entity function as part of its implementation. For the simplest testing experience, a manual trigger function is recommended.

What is the difference between Azure functions and durable functions?

Durable Functions is an extension of Azure Functions that lets you write stateful functions in a serverless compute environment. The extension lets you define stateful workflows by writing orchestrator functions and stateful entities by writing entity functions using the Azure Functions programming model.

What is durable orchestration?

Whenever an activity function is scheduled, the Durable Task Framework checkpoints the execution state of the function into some durable storage backend (Azure Table storage by default). This state is what's referred to as the orchestration history.

Can we call one azure function from another?

In case you need to call another function directly you can choose HTTP protocol, and send your request to the endpoint of the other function or choose to use Durable Functions. In case it is indirect or asynchronous you can choose to use a queue.


1 Answers

Yes, what you're doing is perfectly safe because it still results in deterministic behavior. As long as you aren't doing any custom thread scheduling or calling non-durable APIs that have their own separate async callbacks (for example, network APIs typically have callbacks running on a separate thread), you are fine.

If you are ever unsure, I highly recommend you use our Durable Functions C# analyzer to analyzer your code for coding errors. This will help flag any coding mistakes that could result in Non-deterministic workflow errors.

UPDATE

Note: the current version of the analyzer will require you to add a [Deterministic] attribute to your private async function, like this:

[Deterministic]
private static async Task WriteStatusAsync(
    DurableOrchestrationContextBase context,
    string status,
    ILogger log
)
{
   // ...
}

This lets it know that the private async method is being used by your orchestrator function and that it also needs to be analyzed. If you're using Durable Functions 1.8.3 or below, the [Deterministic] attribute will not exist. However, you can create your own custom attribute with the same name and the analyzer will honor it. For example:

[Deterministic]
private static async Task WriteStatusAsync(
    DurableOrchestrationContextBase context,
    string status,
    ILogger log
)
{
   // ...
}

// Needed for the Durable Functions analyzer
class Deterministic : Attribute { }

Note, however, that we are planning on removing the need for the [Deterministic] attribute in a future release, as we're finding it may not actually be necessary.

like image 66
Chris Gillum Avatar answered Sep 18 '22 15:09

Chris Gillum