处理 Durable Functions 中的错误 (Azure Functions)

Durable Function 业务流程采用代码实现,并可使用编程语言的内置错误处理功能。 实际上,不需要学习任何新概念,就可以将错误处理和补偿添加到业务流程中。 但应注意以下事项。

注意

适用于 Azure Functions 的 Node.js 编程模型版本 4 处于预览阶段。 新版 v4 模型旨在为 JavaScript 和 TypeScript 开发人员提供更为灵活和直观的体验。 在升级指南中详细了解 v3 和 v4 之间的差异。

在以下代码片段中,JavaScript (PM4) 表示编程模型 V4,即新体验。

活动函数中的错误

活动函数中引发的任何异常都将封送回业务流程协调程序函数,并作为 FunctionFailedException 引发。 可在业务流程协调程序函数中编写满足需要的错误处理和补偿代码。

例如,考虑使用以下业务流程协调程序函数,将一个帐户中的资金转到另一帐户:

[FunctionName("TransferFunds")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var transferDetails = context.GetInput<TransferOperation>();

    await context.CallActivityAsync("DebitAccount",
        new
        {
            Account = transferDetails.SourceAccount,
            Amount = transferDetails.Amount
        });

    try
    {
        await context.CallActivityAsync("CreditAccount",
            new
            {
                Account = transferDetails.DestinationAccount,
                Amount = transferDetails.Amount
            });
    }
    catch (Exception)
    {
        // Refund the source account.
        // Another try/catch could be used here based on the needs of the application.
        await context.CallActivityAsync("CreditAccount",
            new
            {
                Account = transferDetails.SourceAccount,
                Amount = transferDetails.Amount
            });
    }
}

注意

前面的 C# 示例适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

如果第一个 CreditAccount 函数调用失败,业务流程协调程序函数将通过将资金贷记回源帐户进行补偿。

失败时自动重试

调用活动函数或子业务流程函数时,可指定自动重试策略。 以下示例尝试调用某函数多达三次,每次重试之间等待 5 秒:

[FunctionName("TimerOrchestratorWithRetry")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var retryOptions = new RetryOptions(
        firstRetryInterval: TimeSpan.FromSeconds(5),
        maxNumberOfAttempts: 3);

    await context.CallActivityWithRetryAsync("FlakyFunction", retryOptions, null);

    // ...
}

注意

前面的 C# 示例适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

上一示例中的活动函数调用使用一个参数来配置自动重试策略。 可通过多种选项自定义自动重试策略:

  • 最大尝试次数:尝试的最大次数。 如果设置为 1,则不会重试。
  • 首次重试间隔:首次尝试重试前需要等待的时间。
  • 回退系数:用来确定回退增加速率的系数。 默认值为 1。
  • 最大重试间隔:尝试重试之间需要等待的最长时间。
  • 重试超时:执行重试所花费的最长时间。 默认行为是可无限期重试。

自定义重试处理程序

使用 .NET 或 Java 时,你还可以选择在代码中实现重试处理程序。 当声明性重试策略表达不够时,这非常有用。 对于不支持自定义重试处理程序的语言,你仍可选择使用循环、异常处理和用于在重试之间注入延迟的计时器来实现重试策略。

RetryOptions retryOptions = new RetryOptions(
    firstRetryInterval: TimeSpan.FromSeconds(5),
    maxNumberOfAttempts: int.MaxValue)
    {
        Handle = exception =>
        {
            // True to handle and try again, false to not handle and throw.
            if (exception is TaskFailedException failure)
            {
                // Exceptions from TaskActivities are always this type. Inspect the
                // inner Exception to get more details.
            }

            return false;
        };
    }

await ctx.CallActivityWithRetryAsync("FlakeyActivity", retryOptions, null);

函数超时

如果业务流程协调程序函数内的函数调用耗时太长才能完成,建议放弃该函数调用。 当前执行此操作的正确方法是使用“any”任务选择器创建持久计时器,如下例中所示:

[FunctionName("TimerOrchestrator")]
public static async Task<bool> Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    TimeSpan timeout = TimeSpan.FromSeconds(30);
    DateTime deadline = context.CurrentUtcDateTime.Add(timeout);

    using (var cts = new CancellationTokenSource())
    {
        Task activityTask = context.CallActivityAsync("FlakyFunction");
        Task timeoutTask = context.CreateTimer(deadline, cts.Token);

        Task winner = await Task.WhenAny(activityTask, timeoutTask);
        if (winner == activityTask)
        {
            // success case
            cts.Cancel();
            return true;
        }
        else
        {
            // timeout case
            return false;
        }
    }
}

注意

前面的 C# 示例适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

注意

此机制实际上不会终止正在进行的活动函数执行。 它只是允许业务流程协调程序函数忽略结果并继续运行。 有关详细信息,请参阅计时器文档。

未经处理的异常

如果业务流程协调程序函数失败,出现未经处理的异常,则会记录异常的详细信息,且实例的完成状态为 Failed

后续步骤