Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅
中国的 Amazon Web Services 服务入门
(PDF)。
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 {'should_retry': False}
# Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s)
delay = min(2 * (2 ** (attempt_count - 1)), 300)
return {'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 {'should_retry': False}
return {'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 {'should_retry': False}
# Exponential backoff: 1s, 2s, 4s (capped at 30s)
delay = min(2 ** (attempt_count - 1), 30)
return {'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 遇到基础设施故障、运行时错误或者 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 中跟踪步骤重试操作及执行失败情况,以识别模式并优化重试策略。