Digdag Release 0.9.37 で確認。
TL;DR
- requireオペレータを安易に利用していたらsession_timeが競合して死んだ
- session_timeとschedule設定の仕様を正しく理解しましょう
- 公式ドキュメントは読みましょう
何が起こったか
1日1回ずつ動かしたい2つのワークフロー[A.dig/B.dig]から共通のdigファイル[C.dig]をrequireする設計で運用を開始。
が、 なぜか片方だけが動作していない…。
それぞれのdigファイルの中身はこんな感じ。
schedule:
daily>: 08:30:00
skip_on_overtime: true
skip_delayed_by: 1s
~~
+require-C:
require>: C.dig
schedule:
daily>: 18:00:00
skip_on_overtime: true
skip_delayed_by: 1s
~~
+require-C:
require>: C.dig
+main:
sh>: hoge.sh
原因は何だったか
A.dig、B.digともにdailyオプションでschedule指定をしていたため、session_timeが両者ともに00:00:00 となっていた。
requireは親となるワークフローのsession_timeで子ワークフローを起動する ため、C.digが同一のsession_timeで2回呼び出されることとなり、時系列順で後の処理が不発となっていた。
挙動をまとめてみる
- scheduleのパラメータについて
ドキュメントにはちゃんと書いてあります。が、完全に見逃していました。
session_timeが00:00:00(または00:00)となる挙動は、dailyだけでなくhourly/weekly/monthlyオプションでも同様です。
https://docs.digdag.io/scheduling_workflow.html?highlight=minutes_interval#setting-up-a-schedule
When you use hourly, daily, weekly or monthly, a session time may not be same with actual run time.
The session time is actual run day’s 00:00:00 (in case hourly, hour’s 00:00).
- requireについて
requireの際にデフォルトで子ワークフローに自分のsession_timeを渡す挙動についてはドキュメント中に確認できませんでした。
下記のワークフローを用意して検証します。
| workflow_name | schedule |
|:--|:--|:--|
| Parent1 | hourly>: 10:00 |
| Parent2 | hourly>: 15:00 |
| Parent3 | cron>: 20 * * * * |
| Parent4 | minutes_interval>: 11 |
| Child1 | N/A |
| Child2 | hourly>: 40:00 |
| Child3 | cron>: 45 * * * * |
| Child4 | minutes_interval>: 13 |
各Childは自身のsession_timeを出力するだけのワークフロー。
各Parentが全ての各Childをrequireしています。
結果が以下。(mm:ssのみ記載)
workflow_name | itself | required by Parent1 | required by Parent2 | required by Parent3 | required by Parent4 |
---|---|---|---|---|---|
Child1 | N/A | 00:00 | 00:00 | 20:00 | 11*N:00 |
Child2 | 00:00 | 00:00 | 00:00 | 20:00 | 11*N:00 |
Child3 | 45:00 | 00:00 | 00:00 | 20:00 | 11*N:00 |
Child4 | 13*N:00 | 00:00 | 00:00 | 20:00 | 11*N:00 |
やはり親のsession_timeが使われるようです。
補足1) Child2についてはParent1(またはParent2)が同一session_timeで先に起動してしまうため、Child2自身のスケジュールで起動することはありません。
補足2) Parent4とChild4は00:00のsession_timeが競合します。cron記法に則り00:00がスケジュールの起点となるため。
- callについて
callオペレータを使った場合も親のsession_timeに準じますが、親のサブタスクとなるのでそのsession_timeで子ワークフローが実行されたという記録は残りません。
また、公式ドキュメントにもあるように多重実行制御は行われません。
解決
多重実行制御してくれる便利なrequire!callの上位互換!という誤った認識を改めcallオペレータに置き換えました。
またはcronパラメータに置き換えてもいいはずです。むしろ最初からcronパラメータだけを使うのが安全かもしれません。
さらなる解法としてrequire時にsession_timeをオプションとして明示的に渡す方法もあります。
多重実行制御を行いたい、かつhourly等のパラメータを使いたいという場合は工夫が必要でしょう。そんなケースは思い当たりませんが。
参考
Digdagのrequireオペレーターの挙動
https://qiita.com/shiozaki/items/b3aaff926b7b601b4f86 参考にさせていただきました。
公式ドキュメントがもうちょっと充実してくれるといいなー。