GitHub Actionsのconcurrencyでrunがcancelledになるときは、実行中runが中断されたのか、待機中runが新しいrunへ置き換わったのかを分けます。cancel-in-progressがfalseでも、既定queueでは古いpendingが残る保証はありません。解決後のgroup値と、どのrunが同じgroupへ入ったかを時刻順に確認します。
この記事は既存workflowの同時実行制御の診断を扱います。workflowの変更・実行・取消、deployment、外部処理の復旧は行っていません。run A/B/Cの例は架空で、GitHub上で挙動を再現した結果ではありません。GitHub.comと利用中のEnterprise Server等で採用できる構文が同じかも確認してください。
目次
cancelled直前のrunを探す
対象run ID、workflow、job、event、ref、commit、開始・待機・取消時刻を並べます。UIのconclusionだけでなく、concurrencyに関するlogや表示と、直前に同じgroupへ入ったrunを照合します。手動取消やtimeoutなど、別の理由も同じcancelled表示になるためです。
表は横にスクロールできます
| 観測 | 先に見る設定 | 別の確認 |
|---|---|---|
| 実行中のAがBで止まる | cancel-in-progress | Aの外部副作用 |
| pendingのBがCで消える | queueの既定・値 | Aは走り続けていないか |
| 別workflowで相互に止まる | 解決後groupの衝突 | 共有が意図したものか |
| 設定後に起動できない | queueとcancelの組合せ | 構文対応・validation error |
workflow-levelとjob-levelのconcurrencyを両方使う場合も、どの単位の制御で待っているかを区別します。表面上同じ名前のjobでも、workflow全体が待機中なら原因箇所が違います。
groupは式ではなく、評価された値で比べる
GitHub公式concurrencyガイド(新しいタブで開く)は、同じrepository内で同じgroupを使うworkflowやjobが制御対象になると説明しています。workflowファイルを分けても、共通の固定名なら互いに影響する可能性があります。
group名は大文字・小文字を区別しません。Productionとproductionを別の排他単位にしたつもりでも、分離にはなりません。branch名やPR番号などを使うなら、pushとPRで利用できるcontextが違う点を確認し、欠けた値で意図せず同じgroupに集まらないかを見ます。
通常CIをworkflowとrefごとに分ける設計と、複数workflowから同じ配布先を守るため共通groupにする設計は、目的が違います。衝突を避けようとして何でも別groupにすると、守る必要のある共有resourceへ同時に処理することになります。何を直列化したいかを先に決めます。
running取消とpending置換を区別する
Workflow syntaxのconcurrency仕様(新しいタブで開く)では、通常は同groupで一つがrunningになります。既定のqueue singleはpendingも一つなので、新しいrunが来ると、古いpendingがcancelされ置き換わります。cancel-in-progressは、runningも取り消すかを指定する別の条件です。
架空のAがrunning、Bがpendingの間にCが入る例では、既定queueならBがCへ置き換わる可能性があります。runningのAまで止める設定でなければ、Aを走らせたままでもBは消えます。この違いを見ずに「falseなのに取消はbug」と判断しないようにします。
表は横にスクロールできます
| 保ちたい挙動 | 確認する方針 | 合わない用途 |
|---|---|---|
| 最新変更のCIを優先 | 古いrunの取消を許すか | 全入力を一件ずつ必ず処理 |
| すべての対象を順に扱う | pending queueと容量 | 最新一件へ置換する既定 |
| 共有先へ一度に一処理 | resourceに対応するgroup | workflow名だけで分離 |
| 外部処理の完了を守る | 取消後の照合・再開 | 取消すれば自動rollback |
queue maxは無制限保存ではない
現在の公式構文は、queue maxで最大100のpendingを待機させる方法を案内しています。満杯なら追加runはcancelされ、cancel-in-progress trueとの併用はvalidation errorになります。古い「pendingは必ず一件だけ」という説明をすべての設定へ当てはめないようにします。
一方、待機順はconcurrency待ちに入った時点によるため、workflowのdispatch順と完全に一致する業務queueとは考えません。すべての業務入力を厳密な順序で処理する必要があるなら、外部queueや処理状態を含めた設計を別に検討します。queue maxへの変更だけで、欠落・重複・順序をすべて解決したとはしません。
取消済みrunの外部状態を照合する
runのcancelは、外部へ行った書込や配布を取り消す保証ではありません。最後に完了したstep、応答を失った要求、生成された成果物、外部側の対象IDを確認します。状態が不明な作成・送信を、再実行で二重にしないことが必要です。
架空例で、外部への登録は済んだが確認step前にcancelされた場合、未登録として最初から作り直すと重複します。処理IDと外部の現在状態を照合し、未実行・完了・結果不明に分けます。concurrencyの修正と、すでに発生した部分成功の復旧は別の作業として記録します。
小さな条件で方針を検証する
許可された検証では、外部送信を伴わない待機用jobなどで、A running/B pending/C到着を区別して観測します。実業務のdeploymentや通知を大量に起動して試す必要はありません。default single、running取消を有効にした場合、対応するmax設定など、採用する条件だけを確認します。
変更前のgroup式・queue・cancel条件と、採用した設定を保存します。取消の件数が減っただけで成功にせず、必要なrunが処理されたか、待機が際限なく延びていないか、同時処理してはいけないresourceが守られたかを確認します。意図しない並行処理が増えたなら設定を戻し、保留・取消済み対象を処理IDで整理してから再開します。
