問題点500MBのCSVファイルを処理したり、複雑な四半期レポートを生成したりするために設計されたLambda関数があるとします。負荷を処理するために、Lambdaの内部タイムアウトを賢明にも15分に設定しました。しかし、Step Functions経由で実行した途端、タスクはちょうど1分後に失敗します。実行履歴に次のエラーが表示されます:
States.HeartbeatTimeout: State machine execution failed: Task timed out after 60 seconds
これは非常に厄介です。なぜなら、Lambdaはバックグラウンドでまだ正常に動作している可能性があるからです。問題はLambdaがクラッシュしたことではなく、Step Functionsが待機を諦めたことにあります。
発生理由Step Functionsはタスクを管理するために2つの異なるタイマーを使用します。安定したワークフローを構築するには、この違いを理解することが重要です。
- TimeoutSeconds: これは絶対的な上限です。タスクの開始から終了までに許容される合計時間を定義します。タスクがこの制限に達すると、強制終了されます。- HeartbeatSeconds: これは「デッドマンズスイッチ(生存確認)」のようなものだと考えてください。タスクが停止していないことを証明するために、定期的に報告することを期待します。この期間内にタスクがハートビートを送信しない場合、Step Functionsはワーカーが停止したと判断し、ステートを終了させます。
States.HeartbeatTimeoutエラーが発生するのは、Amazon States Language (ASL) 定義にHeartbeatSecondsの値が含まれているにもかかわらず、Lambdaがチェックイン(生存報告)を行っていないためです。Step Functionsから見ると、標準的なLambda関数は「投げっぱなし(fire and forget)」です。データを処理している間、自動的にハートビートを送信することはありません。
ステップバイステップの修正方法### ステップ1:ASL定義の確認ワークフロー定義内で失敗しているステートを探します。多くの場合、IDEのプラグインやスニペットによって、デフォルトで60秒のハートビートが自動的に含まれてしまっています。通常、以下のようになっています:
"ProcessLargeData": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:data-processor",
"HeartbeatSeconds": 60,
"End": true
}
ステップ2:ハートビート要件の削除ほとんどのLambdaタスクにおいて、ハートビートは必要ありません。Lambdaは独自のコンピューティングライフサイクルを管理しているため、Step Functionsは最終的なレスポンスを待つだけで十分です。
最善の修正策: HeartbeatSecondsの行を完全に削除してください。代わりに、結果を待機する時間を定義するためにTimeoutSecondsを使用します。
"ProcessLargeData": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:data-processor",
"TimeoutSeconds": 900,
"End": true
}
この例では、Lambda関数の最大実行時間に合わせて、タイムアウトを900秒(15分)に設定しています。
ステップ3:Lambda設定の同期よくある落とし穴は、Step Functionsを更新したのにLambdaの設定を忘れてしまうことです。Step Functionsが15分待機するように設定されていても、Lambdaが30秒のタイムアウトで構成されている場合、Lambdaはやはり失敗します。AWS CLIを使用して、これらが一致していることを確認してください:
aws lambda update-function-configuration \
--function-name data-processor \
--timeout 900
動作確認新しい実行をトリガーして変更をテストします。AWSコンソールのGraph Inspectorを開き、タスクを選択します。以前の60秒の壁を越えて「実行中(Running)」状態(青色)が維持されるはずです。最後に、CloudWatch Logsを確認して、Lambdaがステートマシンにペイロードを正常に返したことを確認します。
どのような場合にハートビートを使用すべきか?ハートビートは無意味なものではありません。単に単純なLambda呼び出し向けではないだけです。以下の2つのシナリオで使用してください:
- Activity Workers: EC2インスタンスやオンプレミスサーバー上でコードを実行し、Step Functionsにポーリングして仕事を取得している場合、そのサーバーがオフラインになったことを検知するためにハートビートが不可欠です。- The Callback Pattern: タスクに人間による承認ステップが含まれる場合や、完了までに数時間かかるジョブの場合は、
.waitForTaskTokenを使用します。この場合、ワーカーは実行を維持するために定期的にSendTaskHeartbeatAPIを呼び出す必要があります。Lambdaを使用する標準(Standard)またはエクスプレス(Express)ワークフローの場合は、TimeoutSecondsのみを使用し、シンプルに保ちましょう。

