2

I'm using Azure Functions V4. In an orchestration (MyCustomOrchestration) I do a fan-out and call an ActivityTriggered-function (HandleIdFunction). The fan-out will usually contain around 20 tasks. The HandleIdFunction is called with a RetryOptions and can throw different exceptions. The retry should retry if any exception is thrown, except for MyCustomError. If MyCustomError is thrown all tasks should be aborted and stop retrying, no matter what exception they may throw. I don't seem to get it to work. The retries keep retrying.

I could not find a way to pass a CancellationToken. And if I set a variable in Handle it will be reset during replay.

Complete reproducable example below:

public class MyCustomError : Exception
{

}

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
          [DurableClient] IDurableClient starter,
        ILogger log)
    {
        var result = await starter.StartNewAsync(nameof(MyCustomOrchestration));
        return new OkObjectResult(result);
    }

    [FunctionName(nameof(HandleIdFunction))]
    public static async Task HandleIdFunction([ActivityTrigger] IDurableActivityContext context)
    {
        var input = context.GetInput<int>();
        Console.WriteLine($"{nameof(HandleIdFunction)} - {input}.");
        await Task.Delay(1000);
        // Fake errors.
        if (input == 10)
            throw new MyCustomError();
        if (input % 2 == 0)
            throw new Exception();
    }

        [FunctionName(nameof(MyCustomOrchestration))]
    public static async Task MyCustomOrchestration([OrchestrationTrigger] IDurableOrchestrationContext context)
    {
        var parallelTasks = new List<Task<Guid>>();

        var retryOptions = new RetryOptions(TimeSpan.FromSeconds(5), 30)
        {
            BackoffCoefficient = 1.85,
            MaxRetryInterval = TimeSpan.FromSeconds(5),
            RetryTimeout = TimeSpan.FromMinutes(1),
            Handle = exception =>
            {
                Console.WriteLine("Retry handled called");
                return (exception.InnerException is not MyCustomError);
            }
        };

        int[] idBatch = Enumerable.Range(0, 20).ToArray();
        for (int i = 0; i < idBatch.Length; i++)
        {
            var id = idBatch[i];
            Task<Guid> task = context.CallActivityWithRetryAsync<Guid>(nameof(HandleIdFunction), retryOptions, id);
            parallelTasks.Add(task);
        }

        Guid[] result = null;

        try
        {
            result = await Task.WhenAll(parallelTasks);
        }
        catch (Exception ex) when (ex.InnerException is MyCustomError)
        {
            // Custom handling.
        }
        catch (Exception ex)
        {
            // Custom handling.
        }
    }
}
smoksnes
  • 10,509
  • 4
  • 49
  • 74

0 Answers0