Workflow SDK 5のキャンセル対応: 長いAIジョブには「中断契約」が必要になる

Tech

長いAIジョブの難しさは、時間がかかることだけではありません。止めるべき瞬間に、何がまだ動いているのか説明できないことです。ユーザーがキャンセルしてもモデル呼び出しが続き、タイムアウト後にアップロードが完了し、クォータ超過後にretryがさらに費用を使うことがあります。

Vercelは2026年6月16日、Workflow SDK 5 betaで標準のAbortControllerとAbortSignalがworkflowとstepの境界を越えて使えると発表しました。同じ流れでSandboxの実行時間も長くなっています。長く走れるなら、正確に止まれる設計が必要です。

Workflow SDKでAbortControllerのsignalが各stepに渡され、タイムアウト、ユーザーキャンセル、クォータ超過で中断される構成図
重要なのはキャンセルボタンではなく、どのstepがどのsignalを受け、どの状態と後始末を残すかという運用契約です。

何が変わったか

workflow内でAbortControllerを作り、そのsignalをstepへ渡し、timeout、race、hook、quota monitorの判断でabort()できます。公式ドキュメントは、signalがsuspension、deterministic replay、別function invocationをまたいでdurableに保たれると説明しています。

ただしcancelはcooperativeです。stepがfetchへsignalを渡す、signal.throwIfAborted()を呼ぶ、signal.abortedを確認するなどの参加が必要です。

なぜ重要か

OCR、レポート生成、ブラウザ自動化、マルチモデルagent、E2E testは長い実行時間を必要とします。キャンセル契約が弱いと、token、API呼び出し、ロック、重複webhook、不明瞭な状態が増えます。

コミュニティではproduction readyか、実行中workflowをどうcancel/cleanupするかという質問が見られます。問題は文法ではなく運用モデルです。

運用への影響

timeoutを製品ポリシーとしてコードに近づけられます。並列providerでは勝者が決まった後に敗者をabortできます。abort errorがretryされないことは、意図した中断と障害を分ける助けになります。

チェックリスト

user cancel、timeout、admin stop、quota exceeded、parent request closeを分けて定義します。

高コストstepはsignalを受け取り、対応APIへ渡します。

run.cancel()とAbortSignalを混同しません。

cancelled_by_user、timed_out、quota_exceededを別状態として保存します。

partial upload、外部job、mail、webhookの後始末をテストします。

リスク

Workflow SDK 5はbeta/pre-releaseです。重要業務では小さく検証し、version pinとrollbackを準備します。

Signalを無視するlibraryやCPU-bound loopは止まりません。外部副作用も巻き戻りません。

今やること

既存の長時間AI要求やagent taskについて、費用を使うstep、外部状態を変えるstep、retryしてはいけないstepを先に可視化してください。

導入前30分チェック

キャンセル理由がプロダクト用語で定義されている

高コストstepがsignalを受け取るか検査する

abortとretryの方針が衝突しない

外部副作用にidempotency keyがある

監視でcancelledとfailedを分ける

const controller = new AbortController();
const result = await Promise.race([
  expensiveStep(controller.signal),
  sleep("30s").then(() => null),
]);
if (result === null) controller.abort();

出典と参考リンク