Dev Study
AWSサービスの内部原理 コース

89. タスクには3つの待ち方がある — 即答・完了待ち・呼び戻しをResourceの接尾辞が切り替える

Task状態が外部サービスと付き合うとき、実は「いつ次の状態へ進むか」という1つの問いしかありません。その答えがResourceフィールドの接尾辞に現れる——この対応を図で追っていきます。

① そもそもResourceは「本物のリソース」を指していない

Resource値arn:aws:states:::sns:publish
つまり
statesSFnの名前空間
:::region/account-idが空
実行環境から推論されるので書かなくてよい
sns:publish呼ぶアクション
統合用の名前ARN形式だが実在リソースを指さない
例外: レガシーLambda統合だけは実在の関数を指す
  • 公式の言い回し——「An ASL Resource value in Step Functions is a unique name (URI) which conforms to ARN format, but typically does not identify an actual Resource in your account.」
  • arn:aws:states: というプレフィックスが「Step Functionsが統合に使う名前空間(namespace)」を張り、::: の空フィールドはワークフローが動くリージョン/アカウントから推論される(だから書かなくてよい)
  • レガシーなLambda統合の例外は、現在のグラフィカルUIでは作成・編集できない——ASLコードを直接編集する場合を除く

Resourceは実在リソースへのポインタではなく、統合のための名前空間上の名前。だからこそ、この名前の末尾に「接尾辞」を足すだけで挙動を切り替えられる。

② 接尾辞なし = Request/Response(既定):HTTPが返ったら即、次へ

Task状態接尾辞なし
arn:aws:states:::sns:publish
ジョブの完了は待たない
HTTP応答返った"瞬間"がトリガー
次の状態へ即進む
  • 公式——「Call a service and Step Functions will progress to the next state immediately after it receives an HTTP response.」「Step Functions will not wait for a job to complete.」
  • 全サービスで使え、StandardでもExpressでも動く唯一のパターン
  • SNSの例なら、Publish APIを呼んだ後すぐ次の状態へ進む——メッセージが受理されたことは分かるが、その先の配信は見届けない

既定は「呼びっぱなし」。APIが応答を返した=受理された時点で次へ進み、その先の仕事の完了は見届けない。

③ .sync = Run a Job:「やって終わる仕事」の完了まで待つ

.sync付きTaskbatch:submitJob.sync
末尾の .sync が挙動を変える
完了まで監視し続ける
一時停止応答が返っても進まない(pause)
完了を確認して
ジョブ完了ここで初めて再開
次の状態へ
  • 公式——「Having the .sync portion appended to the resource ARN means that Step Functions waits for the job to complete.(中略)the workflow pauses. When the job is complete, Step Functions progresses to the next state.」
  • BatchのsubmitJobやECSタスクのように「投入して、終わりがある仕事」に使う
  • .sync と .waitForTaskToken はStandardワークフローのみ
  • .syncに対応するのは最適化統合の一部だけ(例: Batch/ECS/Glue/Athena/EMR系/SageMaker AI/CodeBuild/Step Functions自身は対応、SNS/SQS/Lambda/API Gateway/DynamoDBは非対応)。AWS SDK統合では .sync は使えない

接尾辞 .sync ひとつで「呼びっぱなし」が「完了待ち」に変わる。同期呼び出しに切り替わったのだ。

④ .syncの裏側:どうやって「完了」を知るのか

.syncタスクジョブの終わりを見張る必要がある
監視の道具は2つ: イベント+ポーリング
どちらもポーリング分は
同一アカウントEventBridgeイベント(プッシュ)+APIポーリング(プル)を併用
クロスアカウントポーリングのみ(イベント経路が使えない)
例: states:StartExecution.sync → DescribeExecutionを叩く
クォータ消費あなたの割当クォータを使う(.sync全般の性質)
  • 公式——「When you use the .sync service integration pattern, Step Functions uses polling that consumes your assigned quota and events to monitor a job's status. For .sync invocations within the same account, Step Functions uses EventBridge events and polls the APIs that you specify in the Task state. For cross-account .sync invocations, Step Functions only uses polling.(中略)for states:StartExecution.sync, Step Functions performs polling on the DescribeExecution API and uses your assigned quota.」
  • メッセージング編で見た2つの語彙そのもの——EventBridgeは「イベントが来たら教えてもらう」プッシュ型、ポーリングは「終わった?と繰り返し訊きにいく」プル型
  • ポーリングによるクォータ消費はクロスアカウント限定ではなく .sync 全般の性質。クロスアカウントの違いは「プッシュ経路が使えずポーリング一択」になる点

「完了待ち」の中身は、実行系がイベント+ポーリングで肩代わりする監視。誰が完了を見張るかが、Request/Responseとの決定的な違い。

⑤ .syncの落とし穴:中止されても、ジョブは止められるとは限らない

実行の停止ステートマシンの実行が停止された
Parallel別枝未捕捉で失敗
Map反復未捕捉で失敗
結果は保証されない
キャンセル試行ベストエフォート(best-effort)
例: states:startExecution.sync なら StopExecution APIを呼ぶ
成功ジョブも止まる
失敗しうるジョブは動き続け、追加課金の可能性
理由: IAM実行ロールの権限不足、一時的なサービス障害など
  • 公式——「Step Functions will make a best-effort attempt to cancel the task. For example, if a Step Functions states:startExecution.sync task is aborted, it will call the Step Functions StopExecution API action. However, it is possible that Step Functions will be unable to cancel the task.」
  • 止められない理由として「Your IAM execution role lacks permission to make the corresponding API call.」「A temporary service outage occurred.」が挙げられている(これらに限らない、とも)
  • 止められなければ「you might incur additional charges from the integrated service.」

「完了を待つ」ことと「止められる」ことは別問題。キャンセルはあくまでベストエフォートで、権限や障害次第で統合先のジョブは走り続ける。

⑥ .waitForTaskToken = Wait for Callback:トークンが返るまで待つ

3つ目の接尾辞sqs:sendMessage.waitForTaskToken
トークンは $$.Task.Token でContextオブジェクトから取り出す
外部が SendTaskSuccess / SendTaskFailure でトークンを返す
一時停止外部の処理・人・レガシー系の応答待ち
完了を宣言されて
トークン受領ここで初めて再開
次の状態へ
  • 公式——「The task will pause until it receives that task token back with a SendTaskSuccess or SendTaskFailure call.」
  • トークンは実行のContextオブジェクトから $$.Task.Token で取り出してParameters経由で外部へ渡す
  • 放置対策にHeartbeat(例: "HeartbeatSeconds": 600)を設定でき、SendTaskSuccess / SendTaskFailure / SendTaskHeartbeat のいずれも期限内に届かなければ States.Timeout で失敗する
  • トークンは同一AWSアカウント内のプリンシパルから返す必要がある(別アカウントから送っても効かない)。詳細は後のコールバック回の主役

3つ目の接尾辞は「呼び戻し待ち」。完了の判断を外部に委ね、トークンが戻るまでいくらでも待つ(上限は実行の1年クォータ)。

⑦ まとめ:選んだパターンは、ASLの接尾辞1つに現れる

接尾辞なしsns:publish
.syncbatch:submitJob.sync
.waitForTaskTokensqs:sendMessage.waitForTaskToken
対応の粗い地図(現行ドキュメント準拠)
即、次へRequest/Response: HTTP応答で進む(完了は待たない)
完了待ちRun a Job: 実行系がイベント+ポーリングで監視
呼び戻し待ちWait for Callback: トークンが返るまで待つ
全サービスStandard & Express 両対応
最適化統合の一部Standardのみ・SDK統合では使えない
SDK統合で広く対応Standardのみ・200超サービス+一部の最適化統合
トークンを載せるパラメータがAPIに必要
  • Lambda編で学んだ視点——「呼び出し方(同期/非同期/ポーリング)で失敗時の責任の持ち主が変わる」——がそのまま効く。Request/Responseは呼びっぱなし(責任は呼び先へ)、.syncは実行系が完了監視を肩代わり、.waitForTaskTokenは外部が完了を宣言するまで待つ
  • API Gateway編の「プロキシは応答をどう待つか」と同型の問い
  • Express は Request/Response のみ対応(welcome.html)

「即答か・完了待ちか・呼び戻し待ちか」という設計判断が、コードの中ではResourceの接尾辞ただ1つに宣言的に畳み込まれている——これがStep Functionsの美しさ。

公式ドキュメントで詳しく ↗