Azure Functions 错误处理和重试

选择编程语言

在 Azure Functions 中处理错误有助于避免丢失数据、避免错过事件并监视应用程序的运行状况。 这也是帮助你了解基于事件的触发器的重试行为的重要方式。

本文介绍了错误处理的常规策略和可用的重试策略。

重要

2022 年 12 月删除了某些触发器的重试策略支持预览版。 支持的触发器的重试策略现已正式发布(正式版)。 本文的 “重试 ”部分列出了当前支持重试策略的扩展。

处理错误

Azure 函数中发生的错误可能来自:

  • 使用内置的 Azure Functions 触发器和绑定
  • 对基础 Azure 服务的 API 的调用。
  • 对 REST 终结点的调用。
  • 对客户端库、包或非Microsoft API 的调用。

为了避免丢失数据或错过的消息,应练习良好的错误处理。 下表介绍了一些建议的错误处理做法,并提供指向详细信息的链接:

建议 详细信息
启用 Application Insights Azure Functions 与 Application Insights 集成,可用于收集错误数据、性能数据和运行时日志。 使用 Application Insights 发现并更好地了解函数执行中发生的错误。 若要了解详细信息,请参阅 Azure Functions 中的监视执行
使用结构化错误处理 捕获和记录错误对于监视应用程序的运行状况至关重要。 任何函数代码的最顶层应包括 try/catch 块。 在 catch 块中,可以捕获并记录错误。 有关可能引发的错误绑定的信息,请参阅本文中的 绑定错误代码 。 根据具体的重试策略,可能还会引发新的异常以再次运行函数。
规划重试策略 Azure Functions 中的多个绑定扩展为重试提供内置支持。 其他人允许定义 Azure Functions 运行时实现的重试策略。 对于不提供重试行为的触发器,请考虑实现自己的重试方案。 有关详细信息,请参阅本文中的 重试
幂等性设计 处理数据时发生错误可能会给函数带来问题,尤其是在处理消息时。 必须考虑错误发生时会发生什么以及如何避免重复处理。 若要了解有关详细信息,请参阅针对完全相同的输入设计 Azure Functions

提示

使用输出绑定时,无法处理访问远程服务时发生的错误。 由于此行为,应验证传递给输出绑定的所有数据,以避免引发任何已知异常。 如果必须能够在函数代码中处理此类异常,则应使用客户端 SDK 访问远程服务,而不是依赖输出绑定。

重试

函数可以使用两种类型的重试:

  • 单个触发器扩展的内置重试行为
  • Azure Functions 运行时提供的重试策略

下表指示哪些触发器支持重试以及配置重试行为的位置。 它还链接到有关来自底层服务的错误的详细信息。

触发器/绑定 重试源 配置
Azure Cosmos DB 重试策略 函数级
Azure Blob 存储 绑定扩展 host.json
Azure 事件网格 绑定扩展 事件订阅
Azure 事件中心 重试策略 函数级
Kafka 重试策略 函数级
Azure 队列存储 绑定扩展 host.json
RabbitMQ 绑定扩展 死信队列
Azure 服务总线 绑定扩展 host.json*
定时器 重试策略 函数级

* 需要 Azure 服务总线扩展版本 5.x。 在较旧的扩展版本中, 服务总线死信队列 实现重试行为。

重试策略

使用 Azure Functions,可以为特定触发器类型定义重试策略。 运行时强制实施这些重试策略。 以下触发器类型当前支持重试策略:

对于 v1 和 v2 Python 编程模型,重试支持是相同的。

Azure Functions 运行时版本 1.x 不支持重试策略。

重试策略指示运行时重新运行失败的执行,直到成功完成或达到最大重试次数。

当支持的触发器类型执行的函数引发未捕获的异常时,将评估重试策略。 最佳做法是,应捕获代码中的所有异常,并针对要导致重试的任何错误引发新异常。

重要

在执行重试策略完成后,才会写入事件中心检查点。 由于此行为,特定分区上的进度会暂停,直到当前批处理完成处理。 有关详细信息,请参阅 使用 Azure Functions 和事件中心进行可靠事件处理

事件中心扩展版本 5.x 支持额外的重试功能,用于 Azure Functions 主机与事件中心之间的交互。 有关详细信息,请参阅clientRetryOptions中的

重试策略

可以配置策略支持的两种重试策略:

允许在每次重试之间运行指定的时间。

使用消耗计划时,只会在函数代码运行时计费。 在上述任一重试策略中,执行之间的等待时间不会计费。

最大重试计数

可以在最终失败之前配置重试函数执行的最大次数。 当前重试计数存储在实例的内存中。

实例可能在每两次重试之间发生故障。 当实例在重试策略实施过程中发生故障时,重试计数会丢失。 发生实例故障时,事件中心触发器可以恢复处理,并在新实例上重试批处理,并将重试计数重置为零。 计时器触发器不会在新实例上恢复。

此行为意味着系统只能尽力完成最大重试次数。 在某些罕见情况下,重试某个执行的次数可能会超过请求的最大次数。 对于计时器触发器,重试次数可以小于请求的最大数目。

重试示例

为固定延迟和指数退避策略提供了示例。 若要查看特定策略的示例,必须先在上一选项卡上选择该策略。

以下 NuGet 包支持函数级重试:

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
    public static class TimerFunction
    {
        //<docsnippet_fixed_delay_retry_example>
        [Function(nameof(TimerFunction))]
        [FixedDelayRetry(5, "00:00:10")]
        public static void Run([TimerTrigger("0 */5 * * * *")] TimerInfo timerInfo,
            FunctionContext context)
        {
            var logger = context.GetLogger(nameof(TimerFunction));
            logger.LogInformation($"Function Ran. Next timer schedule = {timerInfo.ScheduleStatus?.Next}");
        }
        //</docsnippet_fixed_delay_retry_example>
    }
}
资产 DESCRIPTION
MaxRetryCount 必填。 每个函数执行允许的最大重试次数。 值为 -1 表示重试无限次数。
DelayInterval 重试之间使用的延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。

下面是文件中定义的 function.json 重试策略的示例:

{
    "disabled": false,
    "bindings": [
        {
            ....
        }
    ],
    "retry": {
        "strategy": "fixedDelay",
        "maxRetryCount": 4,
        "delayInterval": "00:00:10"
    }
}

可以在重试策略定义上设置这些属性:

资产 DESCRIPTION
策略 必填。 要使用的重试策略。 有效值为 fixedDelayexponentialBackoff
最大重试次数 (maxRetryCount) 必填。 每个函数执行允许的最大重试次数。 -1 表示无限重试。
延迟间隔 使用 fixedDelay 策略时重试之间的延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
最小间隔 使用 exponentialBackoff 策略时的最小重试延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
最大时间间隔 使用 exponentialBackoff 策略时的最大重试延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。

为触发器定义重试策略的方式取决于 Node.js 版本:

下面是使用固定延迟重试策略的计时器触发器函数的示例:

const { app } = require('@azure/functions');

app.timer('timerTriggerWithRetry', {
    schedule: '0 */5 * * * *',
    retry: {
        strategy: 'fixedDelay',
        delayInterval: {
            seconds: 10,
        },
        maxRetryCount: 4,
    },
    handler: (myTimer, context) => {
        if (context.retryContext?.retryCount < 2) {
            throw new Error('Retry!');
        } else {
            context.log('Timer function processed request.');
        }
    },
});

为触发器定义重试策略的方式取决于 Node.js 版本:

下面是使用固定延迟重试策略的计时器触发器函数的示例:

import { app, InvocationContext, Timer } from '@azure/functions';

export async function timerTriggerWithRetry(myTimer: Timer, context: InvocationContext): Promise<void> {
    if (context.retryContext?.retryCount < 2) {
        throw new Error('Retry!');
    } else {
        context.log('Timer function processed request.');
    }
}

app.timer('timerTriggerWithRetry', {
    schedule: '0 */5 * * * *',
    retry: {
        strategy: 'fixedDelay',
        delayInterval: {
            seconds: 10,
        },
        maxRetryCount: 4,
    },
    handler: timerTriggerWithRetry,
});

可以在重试策略定义上设置这些属性:

资产 DESCRIPTION
策略 必填。 要使用的重试策略。 有效值为 fixedDelayexponentialBackoff
最大重试次数 (maxRetryCount) 必填。 每个函数执行允许的最大重试次数。 -1 表示无限重试。
延迟间隔 使用 fixedDelay 策略时重试之间的延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
最小间隔 使用 exponentialBackoff 策略时的最小重试延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
最大时间间隔 使用 exponentialBackoff 策略时的最大重试延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。

下面是使用固定延迟重试策略的计时器触发器函数的示例:

import logging

from azure.functions import AuthLevel, Context, FunctionApp, TimerRequest

app = FunctionApp(http_auth_level=AuthLevel.ANONYMOUS)


@app.timer_trigger(schedule="*/1 * * * * *", arg_name="mytimer",
                   run_on_startup=False,
                   use_monitor=False)
@app.retry(strategy="fixed_delay", max_retry_count="3",
           delay_interval="00:00:01")
def mytimer(mytimer: TimerRequest, context: Context) -> None:
    logging.info(f'Current retry count: {context.retry_context.retry_count}')

    if context.retry_context.retry_count == \
            context.retry_context.max_retry_count:
        logging.info(
            f"Max retries of {context.retry_context.max_retry_count} for "
            f"function {context.function_name} has been reached")
    else:
        raise Exception("This is a retryable exception")

可以在重试策略定义上设置这些属性:

资产 DESCRIPTION
strategy 必填。 要使用的重试策略。 有效值为 fixed_delayexponential_backoff
max_retry_count 必填。 每个函数执行允许的最大重试次数。 值为 -1 表示重试无限次数。
delay_interval 使用 fixed_delay 策略时重试之间的延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
minimum_interval 使用 exponential_backoff 策略时的最小重试延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
maximum_interval 使用 exponential_backoff 策略时的最大重试延迟。 将其指定为一个格式为 HH:mm:ss 的字符串。
@FunctionName("TimerTriggerJava1")
@FixedDelayRetry(maxRetryCount = 4, delayInterval = "00:00:10")
public void run(
    @TimerTrigger(name = "timerInfo", schedule = "0 */5 * * * *") String timerInfo,
    final ExecutionContext context
) {
    context.getLogger().info("Java Timer trigger function executed at: " + LocalDateTime.now());
}

绑定错误代码

与 Azure 服务集成时,错误可能源自底层服务的 API。 以下文章的“异常和返回代码”部分中提供了与特定于绑定的错误相关的信息: