本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
重試 Lambda 耐用函數
耐用的 函數提供自動重試功能,讓您的應用程式能夠適應暫時性故障。開發套件處理兩個層級的重試:商業邏輯故障的步驟重試,以及基礎設施故障的後端重試。
步驟重試
當步驟中發生未攔截的例外狀況時,軟體開發套件會根據設定的重試策略自動重試步驟。步驟重試是檢查點操作,可讓 SDK 暫停執行並在稍後繼續,而不會遺失進度。
步驟重試行為
下表說明 SDK 在步驟中如何處理例外狀況:
| 案例 |
會發生什麼情況 |
計量影響 |
| 步驟中剩餘重試嘗試的例外狀況 |
SDK 會建立重試的檢查點,並暫停函數。在下次調用時,步驟會重試已設定的退避延遲。 |
1 操作 + 錯誤承載大小 |
| 步驟中的例外狀況,沒有剩餘的重試嘗試 |
步驟失敗並擲回例外狀況。如果您的處理常式程式碼未擷取此例外狀況,則整個執行會失敗。 |
1 操作 + 錯誤承載大小 |
當步驟需要重試時,開發套件會檢查重試狀態,並在沒有其他工作執行時結束 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 會將執行標記為 FAILED,並傳回錯誤。系統不會自動重試例外狀況。 |
錯誤承載大小 |
若要啟用易出錯程式碼的自動重試,請使用重試策略將其包裝在步驟中。步驟提供可設定退避的自動重試,而步驟外的程式碼會立即失敗。
後端重試
當 Lambda 遇到基礎設施故障、執行時間錯誤,或開發套件無法與持久的執行服務通訊時,就會發生後端重試。Lambda 會自動重試這些失敗,以確保您的耐用函數可以從暫時性基礎設施問題中復原。
後端重試案例
當函數遇到下列情況時,Lambda 會自動重試函數:
-
內部服務錯誤 - 當 Lambda 或持久性執行服務傳回 5xx 錯誤時,表示暫時服務問題。
-
限流 - 當函數因並行限制或服務配額而限流時。
-
逾時 - 當 SDK 在逾時期間內無法達到持久的執行服務時。
-
沙盒初始化失敗 - 當 Lambda 無法初始化執行環境時。
-
執行時間錯誤 - 當 Lambda 執行時間遇到函數程式碼以外的錯誤,例如out-of-memory錯誤或程序當機。
-
無效的檢查點字符錯誤 - 當檢查點字符不再有效時,通常是由於服務端狀態變更。
下表說明 SDK 如何處理這些案例:
| 案例 |
會發生什麼情況 |
計量影響 |
| 耐用處理常式外的執行時間錯誤 (OOM、逾時、當機) |
Lambda 會自動重試調用。開發套件會從最後一個檢查點重播,略過完成的步驟。 |
錯誤承載大小 + 每次重試 1 個操作 |
呼叫 / GetDurableExecutionState APIs時發生服務錯誤 (5xx) CheckpointDurableExecution 或逾時 |
Lambda 會自動重試調用。開發套件會從最後一個檢查點重播。 |
錯誤承載大小 + 每次重試 1 個操作 |
呼叫 / GetDurableExecutionState APIs 時調節 (429) CheckpointDurableExecution 或無效的檢查點字符 |
Lambda 會自動重試具有指數退避的調用。開發套件會從最後一個檢查點重播。 |
錯誤承載大小 + 每次重試 1 個操作 |
當 / GetDurableExecutionState APIs時,用戶端錯誤 CheckpointDurableExecution (4xx,429 和無效的字符除外) |
SDK 會將執行標記為 FAILED。不會自動重試,因為錯誤表示永久問題。 |
錯誤承載大小 |
後端重試會使用指數退避並繼續,直到函數成功或達到執行逾時為止。在重播期間,軟體開發套件會略過已完成的檢查點,並繼續從上次成功的操作執行,確保您的函數不會重新執行已完成的工作。
重試最佳實務
設定重試策略時,請遵循下列最佳實務:
-
設定明確的重試策略 - 不要依賴生產環境中的預設重試行為。為您的使用案例使用適當的最大嘗試次數和退避間隔來設定明確的重試策略。
-
使用條件式重試 - shouldRetry 實作邏輯僅重試暫時性錯誤 (速率限制、逾時),並在永久錯誤時快速失敗 (驗證失敗,找不到)。
-
設定適當的最大嘗試次數 - 在彈性和執行時間之間取得平衡。太多重試可能會延遲故障偵測,而太少會導致不必要的故障。
-
使用指數退避 - 指數退避可減少下游服務的負載,並提高從暫時性故障中復原的可能性。
-
在步驟中包裝容易出錯的程式碼 - 無法自動重試步驟外部的程式碼。使用重試策略在步驟中包裝外部 API 呼叫、資料庫查詢和其他容易出錯的操作。
-
監控重試指標 - 在 Amazon CloudWatch 中追蹤步驟重試操作和執行失敗,以識別模式並最佳化重試策略。