View a markdown version of this page

Lambda 持久性函数的重试次数 - AWS Lambda

Lambda 持久性函数的重试次数

持久性函数提供自动重试功能,这使您的应用程序能够抵御暂时性的故障。SDK 在两个层面处理重试:一是针对业务逻辑故障的步骤重试;二是针对基础设施故障的后端重试。

步骤重试

当某个步骤中出现未捕获的异常时,SDK 会根据所配置的重试策略自动重试该步骤。步骤重试是检查点操作,它使 SDK 能够暂停执行并稍后恢复,从而不会丢失进度。

步骤重试行为

下表介绍了 SDK 如何在步骤中处理异常情况:

场景 发生了什么 计量影响
剩余重试次数的步骤中出现异常 SDK 会为重试创建检查点并暂停该函数。下次调用时,该步骤按照所配置回退延迟重试。 1 个操作 + 错误有效载荷大小
没有剩余重试次数的步骤中出现异常 步骤失败并引发异常。如果您的处理程序代码未能捕获此异常,则整个执行过程将会失败。 1 个操作 + 错误有效载荷大小

当某个步骤需要重试时,SDK 会对重试状态进行检查点处理,并在没有其他工作正在运行的情况下退出 Lambda 调用。这样,SDK 就可以在不消耗计算资源的情况下实施回退延迟。回退期过后,函数将自动恢复。

配置步骤重试策略

配置重试策略以控制步骤处理失败的方式。您可以指定最大尝试次数、回退间隔和重试条件。

具有最大尝试次数的指数回退:

TypeScript
const result = await context.step('call-api', async () => { const response = await fetch('https://api.example.com/data'); if (!response.ok) throw new Error(`API error: ${response.status}`); return await response.json(); }, { retryStrategy: (error, attemptCount) => { if (attemptCount >= 5) { return { shouldRetry: false }; } // Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s) const delay = Math.min(2 * Math.pow(2, attemptCount - 1), 300); return { shouldRetry: true, delay: { seconds: delay } }; } });
Python
def retry_strategy(error, attempt_count): if attempt_count >= 5: return RetryDecision(should_retry=False) # Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s) delay = min(2 * (2 ** (attempt_count - 1)), 300) return RetryDecision(should_retry=True, delay=delay) result = context.step( lambda _: call_external_api(), name='call-api', config=StepConfig(retry_strategy=retry_strategy) )

固定间隔回退:

TypeScript
const orders = await context.step('query-orders', async () => { return await queryDatabase(event.userId); }, { retryStrategy: (error, attemptCount) => { if (attemptCount >= 3) { return { shouldRetry: false }; } return { shouldRetry: true, delay: { seconds: 5 } }; } });
Python
def retry_strategy(error, attempt_count): if attempt_count >= 3: return RetryDecision(should_retry=False) return RetryDecision(should_retry=True, delay=5) orders = context.step( lambda _: query_database(event['userId']), name='query-orders', config=StepConfig(retry_strategy=retry_strategy) )

有条件重试(仅重试特定错误):

TypeScript
const result = await context.step('call-rate-limited-api', async () => { const response = await fetch('https://api.example.com/data'); if (response.status === 429) throw new Error('RATE_LIMIT'); if (response.status === 504) throw new Error('TIMEOUT'); if (!response.ok) throw new Error(`API_ERROR_${response.status}`); return await response.json(); }, { retryStrategy: (error, attemptCount) => { // Only retry rate limits and timeouts const isRetryable = error.message === 'RATE_LIMIT' || error.message === 'TIMEOUT'; if (!isRetryable || attemptCount >= 3) { return { shouldRetry: false }; } // Exponential backoff: 1s, 2s, 4s (capped at 30s) const delay = Math.min(Math.pow(2, attemptCount - 1), 30); return { shouldRetry: true, delay: { seconds: delay } }; } });
Python
def retry_strategy(error, attempt_count): # Only retry rate limits and timeouts is_retryable = str(error) in ['RATE_LIMIT', 'TIMEOUT'] if not is_retryable or attempt_count >= 3: return RetryDecision(should_retry=False) # Exponential backoff: 1s, 2s, 4s (capped at 30s) delay = min(2 ** (attempt_count - 1), 30) return RetryDecision(should_retry=True, delay=delay) result = context.step( lambda _: call_rate_limited_api(), name='call-rate-limited-api', config=StepConfig(retry_strategy=retry_strategy) )

禁用重试:

TypeScript
const isDuplicate = await context.step('check-duplicate', async () => { return await checkIfOrderExists(event.orderId); }, { retryStrategy: () => ({ shouldRetry: false }) });
Python
is_duplicate = context.step( lambda _: check_if_order_exists(event['orderId']), name='check-duplicate', config=StepConfig( retry_strategy=lambda error, attempt: {'should_retry': False} ) )

当重试策略返回 shouldRetry: false 时,步骤会立即失败,无需重试。将此用于那些不应被重试的操作,例如幂等性检查或具有副作用且无法安全重复的操作。

步骤之外的异常

当在处理程序代码中出现未捕获的异常,且该异常未发生在任何步骤之内时,SDK 会将此次执行标记为失败。这能确保您应用程序逻辑中的错误能够被准确地捕获并报告出来。

场景 发生了什么 计量影响
在任何步骤之外的处理程序代码中出现异常 SDK 将执行标记为 FAILED 并返回错误。异常不会被自动重试。 错误有效载荷大小

为了使易出错的代码能够自动重试,可以将该代码封装在一个带有重试策略的步骤中。步骤提供自动重试和可配置的回退功能,而步骤之外的代码会立即失败。

调用重试

调用级别的重试处理机制,因 Lambda 持久性函数的调用方式而异。下表描述了不同调用类型可能对调用级别重试的影响。

调用类型 发生了什么
同步调用 在持久性函数执行期间,如果出现错误,Lambda 不会自动重试调用。调用失败时的重试次数取决于同步调用的来源。例如,使用 AWS SDK,默认情况下会自动重试 InternalFailure 和 ThrottlingException。
异步调用 如果持久性函数执行失败(例如进入 FAILED、STOPPED 或 TIMED_OUT 状态),则 Lambda 不会重试执行。这与标准 Lambda 函数不同:当异步调用失败时,Lambda 会自动重试标准 Lambda 函数。异步调用的 MaximumRetryAttempts 设置不适用于持久执行。如果为函数配置了死信队列(DLQ),Lambda 会将触发事件发送到 DLQ。
事件源映射(ESM) 默认情况下,Lambda 会持续重试整批任务,直至执行成功。对于流源(DynamoDB 和 Kinesis),可以配置 Lambda 在函数返回错误时重试的最大次数。请参阅事件源映射批处理。对于 Amazon SQS ESM,可通过原始 Amazon SQS 队列绑定的 DLQ 配置最大重试次数。请参阅配置 Amazon SQS ESM。此外,亦可在函数级别配置 DLQ,由 Lambda 将触发失败的事件转发到该 DLQ。请参阅函数 DLQ。若需若需获取全部处理尝试失败或成功的事件记录,可为 ESM 配置目标。请参阅异步调用目标
直接触发器 由触发器类型决定。例如,Lambda 会异步处理由 Amazon S3 事件通知触发的函数。请参阅使用 Lambda 处理 Amazon SQS 事件通知。Lambda 会异步处理由 Amazon SNS 事件通知触发的函数。请参阅使用 Amazon SNS 通知调用 Lambda 函数。异步调用的重试行为,详见上方“异步调用”表格。如果无法联系到 Lambda 或消息被拒绝,Amazon SNS 将在几个小时内以递增的间隔重试。有关详细信息,请参阅 Amazon SNS 常见问题中的可靠性。API Gateway 会同步调用 Lambda,并将原始错误响应返回给请求者。请参阅调用重试。同步调用的重试行为,详见上方“同步调用”表格。有关更多详细信息,请参阅各个直接触发器

后端重试

当 Lambda 遇到基础设施故障、运行时错误或者 SDK 无法与持久执行服务进行通信时,就会出现后端重试。Lambda 会自动重试这些故障,以帮助持久性函数能够从暂时基础设施问题中恢复。

后端重试场景

当 Lambda 遇到以下情况时,会自动重试您的函数:

  • 内部服务错误:当 Lambda 或持久执行服务返回 5xx 错误时,表示存在暂时性的服务问题。

  • 节流:当您的函数因并发限制或服务配额而被限制时。

  • 超时:当 SDK 在超时时间内无法连接到持久执行服务时。

  • 沙盒初始化失败:当 Lambda 无法初始化执行环境时。

  • 运行时错误:当 Lambda 运行时遇到超出您函数代码范围的错误时,例如内存不足错误或进程崩溃等。

  • 无效的检查点令牌错误:当检查点令牌不再有效时,通常是因为服务端状态发生变化所致。

下表描述了 SDK 如何处理这些场景:

场景 发生了什么 计量影响
持久性处理程序之外的运行时错误(OOM、超时、崩溃) Lambda 会自动重试调用。SDK 会从上一个检查点开始重放,以跳过已完成的步骤。 错误有效载荷大小 + 每次重试 1 次操作
调用 CheckpointDurableExecution / GetDurableExecutionState API 时出现服务错误(5xx)或超时 Lambda 会自动重试调用。SDK 会从上一个检查点开始重放。 错误有效载荷大小 + 每次重试 1 次操作
调用 CheckpointDurableExecution / GetDurableExecutionState API时出现节流(429)或无效的检查点令牌 Lambda 会自动通过指数回退重试调用。SDK 会从上一个检查点开始重放。 错误有效载荷大小 + 每次重试 1 次操作
调用 CheckpointDurableExecution / GetDurableExecutionState API 时出现客户端错误(4xx,429 和无效令牌除外) SDK 将执行标记为 FAILED。由于该错误表明存在永久性问题,所以不会自动重试。 错误有效载荷大小

后端重试采用指数回退策略,并持续进行直至函数成功执行或达到执行超时时间。在重放过程中,SDK 跳过已完成的检查点,并从上一次成功的操作处继续执行,从而确保您的函数不会重复执行已完成的工作。

重试最佳实践

在配置重试策略时,请遵循以下最佳实践:

  • 配置明确的重试策略:不要依赖生产环境中的默认重试行为。为您的使用案例配置明确的重试策略,包括适当的最大重试次数和回退间隔。

  • 使用条件重试:实施 shouldRetry 逻辑,以仅对暂时出现的错误(如速率限制、超时)进行重试,而对于永久性的错误(如验证失败、未找到)则启动快速失效机制。

  • 设置适当的最大尝试次数:在韧性与执行时间之间取得平衡。尝试次数过多会延缓故障的检测,而尝试次数过少则可能导致不必要的故障发生。

  • 使用指数回退:指数回退能够减轻下游服务的负载,并提高从暂时性故障中恢复的可能性。

  • 在步骤中封装容易出错的代码:步骤之外的代码无法自动重试。将外部 API 调用、数据库查询以及其他容易出错的操作封装在具有重试策略的步骤中。

  • 监控重试指标:在 Amazon CloudWatch 中跟踪步骤重试操作及执行失败情况,以识别模式并优化重试策略。