もりはやメモφ(・ω・ )

インフラなエンジニアからSREへ

digdagのループ for_each 利用時の _parallel 指定について

digdagのループ for_each 利用時の _parallel 指定について仕様を調べたのでメモ。

公式ドキュメントの Parallel execution にある通り「子タスクには効果があるが、孫タスクには効果が無い」ことを確認します。

If _parallel: true parameter is set to a group, child tasks in the group run in parallel (grandchildren are not affected):

ケース1: _parallel指定無し

_parallelを指定しなかった場合、デフォルトがシーケンシャルのため、全てがシーケンシャルに実行されます。

+testing:
  _export:
    sweet: &SWEETS
      - apple
      - banana
      - candy

  for_each>:
    sweet: *SWEETS

  _do:
    +task1:
      sh>: echo "$(date) - ${sweet} - 1" ; sleep 3

    +task2:
      sh>: echo "$(date) - ${sweet} - 2"

実行ログは以下のとおり。appleの1, 2が行われ、続いてbanana, candyという順に実行されます。

2020-04-15 22:26:29 +0900: Digdag v0.9.41
2020-04-15 22:26:41 +0900 [WARN] (main): Reusing the last session time 2020-04-14T00:00:00+00:00.
2020-04-15 22:26:41 +0900 [INFO] (main): Using session /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000.
2020-04-15 22:26:41 +0900 [INFO] (main): Starting a new session project id=1 workflow name=child session_time=2020-04-14T00:00:00+00:00
2020-04-15 22:26:42 +0900 [INFO] (0017@[0:default]+child+testing): for_each>: {sweet=[apple, banana, candy]}
2020-04-15 22:26:43 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task1): sh>: echo "$(date) - apple - 1" ; sleep 3
Wed Apr 15 22:26:43 JST 2020 - apple - 1
2020-04-15 22:26:46 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task2): sh>: echo "$(date) - apple - 2"
Wed Apr 15 22:26:46 JST 2020 - apple - 2
2020-04-15 22:26:46 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=1=banana+task1): sh>: echo "$(date) - banana - 1" ; sleep 3
Wed Apr 15 22:26:46 JST 2020 - banana - 1
2020-04-15 22:26:50 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=1=banana+task2): sh>: echo "$(date) - banana - 2"
Wed Apr 15 22:26:50 JST 2020 - banana - 2
2020-04-15 22:26:50 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=2=candy+task1): sh>: echo "$(date) - candy - 1" ; sleep 3
Wed Apr 15 22:26:50 JST 2020 - candy - 1
2020-04-15 22:26:53 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=2=candy+task2): sh>: echo "$(date) - candy - 2"
Wed Apr 15 22:26:53 JST 2020 - candy - 2
Success. Task state is saved at /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000 directory.
  * Use --session <daily | hourly | "yyyy-MM-dd[ HH:mm:ss]"> to not reuse the last session time.
  * Use --rerun, --start +NAME, or --goal +NAME argument to rerun skipped tasks.

ケース2: タスクの外で _parallel 指定は意味がない

以下のように、タスクの外で _parallel: true を指定しても効果がないことがわかりました。

_parallel: true

+testing:
  _export:
    sweet: &SWEETS
      - apple
      - banana
      - candy

  for_each>:
    sweet: *SWEETS

  _do:
    +task1:
      sh>: echo "$(date) - ${sweet} - 1" ; sleep 3

    +task2:
      sh>: echo "$(date) - ${sweet} - 2"

ログは以下の通り

2020-04-15 22:30:42 +0900: Digdag v0.9.41
2020-04-15 22:30:54 +0900 [WARN] (main): Reusing the last session time 2020-04-14T00:00:00+00:00.
2020-04-15 22:30:54 +0900 [INFO] (main): Using session /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000.
2020-04-15 22:30:54 +0900 [INFO] (main): Starting a new session project id=1 workflow name=child session_time=2020-04-14T00:00:00+00:00
2020-04-15 22:30:55 +0900 [INFO] (0017@[0:default]+child+testing): for_each>: {sweet=[apple, banana, candy]}
2020-04-15 22:30:56 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task1): sh>: echo "$(date) - apple - 1" ; sleep 3
Wed Apr 15 22:30:56 JST 2020 - apple - 1
2020-04-15 22:30:59 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task2): sh>: echo "$(date) - apple - 2"
Wed Apr 15 22:30:59 JST 2020 - apple - 2
2020-04-15 22:30:59 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=1=banana+task1): sh>: echo "$(date) - banana - 1" ; sleep 3
Wed Apr 15 22:31:00 JST 2020 - banana - 1
2020-04-15 22:31:03 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=1=banana+task2): sh>: echo "$(date) - banana - 2"
Wed Apr 15 22:31:03 JST 2020 - banana - 2
2020-04-15 22:31:03 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=2=candy+task1): sh>: echo "$(date) - candy - 1" ; sleep 3
Wed Apr 15 22:31:03 JST 2020 - candy - 1
2020-04-15 22:31:06 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=2=candy+task2): sh>: echo "$(date) - candy - 2"
Wed Apr 15 22:31:06 JST 2020 - candy - 2
Success. Task state is saved at /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000 directory.
  * Use --session <daily | hourly | "yyyy-MM-dd[ HH:mm:ss]"> to not reuse the last session time.
  * Use --rerun, --start +NAME, or --goal +NAME argument to rerun skipped tasks.

ケース3: タスク内で _parallel 指定はループの要素に効果はあるが、doの中には効果がない

タスクの中で _parallel: true を指定すると apple, banana, candy という各要素についてはパラレルで実行されるが、 _do: で指定したタスクはシーケンシャルで実行されました。子タスク=要素のループで、孫タスク=_doの中のタスクと分かりました。

+testing:
  _parallel: true
  _export:
    sweet: &SWEETS
      - apple
      - banana
      - candy

  for_each>:
    sweet: *SWEETS

  _do:
    +task1:
      sh>: echo "$(date) - ${sweet} - 1" ; sleep 3

    +task2:
      sh>: echo "$(date) - ${sweet} - 2"

以下はログ。apple, banana, candy はパラレルで実行されるため、順番も入れ替わって見えますが、task2 が task1 より先に実行されることはありません。

2020-04-15 22:35:13 +0900: Digdag v0.9.41
2020-04-15 22:35:26 +0900 [WARN] (main): Reusing the last session time 2020-04-14T00:00:00+00:00.
2020-04-15 22:35:26 +0900 [INFO] (main): Using session /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000.
2020-04-15 22:35:26 +0900 [INFO] (main): Starting a new session project id=1 workflow name=child session_time=2020-04-14T00:00:00+00:00
2020-04-15 22:35:27 +0900 [INFO] (0017@[0:default]+child+testing): for_each>: {sweet=[apple, banana, candy]}
2020-04-15 22:35:29 +0900 [INFO] (0018@[0:default]+child+testing^sub+for-0=sweet=1=banana+task1): sh>: echo "$(date) - banana - 1" ; sleep 3
2020-04-15 22:35:29 +0900 [INFO] (0019@[0:default]+child+testing^sub+for-0=sweet=2=candy+task1): sh>: echo "$(date) - candy - 1" ; sleep 3
Wed Apr 15 22:35:29 JST 2020 - candy - 1
Wed Apr 15 22:35:29 JST 2020 - banana - 1
2020-04-15 22:35:29 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task1): sh>: echo "$(date) - apple - 1" ; sleep 3
Wed Apr 15 22:35:29 JST 2020 - apple - 1
2020-04-15 22:35:32 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task2): sh>: echo "$(date) - apple - 2"
2020-04-15 22:35:32 +0900 [INFO] (0019@[0:default]+child+testing^sub+for-0=sweet=1=banana+task2): sh>: echo "$(date) - banana - 2"
Wed Apr 15 22:35:32 JST 2020 - apple - 2
Wed Apr 15 22:35:32 JST 2020 - banana - 2
2020-04-15 22:35:32 +0900 [INFO] (0018@[0:default]+child+testing^sub+for-0=sweet=2=candy+task2): sh>: echo "$(date) - candy - 2"
Wed Apr 15 22:35:32 JST 2020 - candy - 2
Success. Task state is saved at /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000 directory.
  * Use --session <daily | hourly | "yyyy-MM-dd[ HH:mm:ss]"> to not reuse the last session time.
  * Use --rerun, --start +NAME, or --goal +NAME argument to rerun skipped tasks.

ケース4: タスク内でも、do内でも parallel 指定をすると全てがパラレルで実行される

要素についても、タスクについてもパラレルで実行する場合のケースです。

+testing:
  _parallel: true
  _export:
    sweet: &SWEETS
      - apple
      - banana
      - candy

  for_each>:
    sweet: *SWEETS

  _do:
    _parallel: true
    +task1:
      sh>: echo "$(date) - ${sweet} - 1" ; sleep 3

    +task2:
      sh>: echo "$(date) - ${sweet} - 2"

全てが同じ時間に実行されています。

2020-04-15 22:40:14 +0900: Digdag v0.9.41
2020-04-15 22:40:26 +0900 [WARN] (main): Reusing the last session time 2020-04-14T00:00:00+00:00.
2020-04-15 22:40:26 +0900 [INFO] (main): Using session /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000.
2020-04-15 22:40:26 +0900 [INFO] (main): Starting a new session project id=1 workflow name=child session_time=2020-04-14T00:00:00+00:00
2020-04-15 22:40:27 +0900 [INFO] (0017@[0:default]+child+testing): for_each>: {sweet=[apple, banana, candy]}
2020-04-15 22:40:28 +0900 [INFO] (0018@[0:default]+child+testing^sub+for-0=sweet=0=apple+task2): sh>: echo "$(date) - apple - 2"
2020-04-15 22:40:28 +0900 [INFO] (0019@[0:default]+child+testing^sub+for-0=sweet=1=banana+task1): sh>: echo "$(date) - banana - 1" ; sleep 3
Wed Apr 15 22:40:28 JST 2020 - banana - 1
Wed Apr 15 22:40:28 JST 2020 - apple - 2
2020-04-15 22:40:28 +0900 [INFO] (0020@[0:default]+child+testing^sub+for-0=sweet=1=banana+task2): sh>: echo "$(date) - banana - 2"
2020-04-15 22:40:28 +0900 [INFO] (0022@[0:default]+child+testing^sub+for-0=sweet=2=candy+task2): sh>: echo "$(date) - candy - 2"
Wed Apr 15 22:40:28 JST 2020 - banana - 2
Wed Apr 15 22:40:28 JST 2020 - candy - 2
2020-04-15 22:40:28 +0900 [INFO] (0021@[0:default]+child+testing^sub+for-0=sweet=2=candy+task1): sh>: echo "$(date) - candy - 1" ; sleep 3
Wed Apr 15 22:40:28 JST 2020 - candy - 1
2020-04-15 22:40:28 +0900 [INFO] (0017@[0:default]+child+testing^sub+for-0=sweet=0=apple+task1): sh>: echo "$(date) - apple - 1" ; sleep 3
Wed Apr 15 22:40:28 JST 2020 - apple - 1
Success. Task state is saved at /Users/morihaya/work/testdig/.digdag/status/20200414T000000+0000 directory.
  * Use --session <daily | hourly | "yyyy-MM-dd[ HH:mm:ss]"> to not reuse the last session time.
  * Use --rerun, --start +NAME, or --goal +NAME argument to rerun skipped tasks.

まとめ

当たり前ですが、以下のドキュメントの通りの動きを確認できたので満足しました。 ループと _parallel の組み合わせは強力ですが乱用するとキューが詰まって他のWorkflowに影響が出ることもありますので要注意ですね。

If _parallel: true parameter is set to a group, child tasks in the group run in parallel (grandchildren are not affected):