LoginSignup
5
2

More than 5 years have passed since last update.

失敗したrequireオペレーターをリトライする時の罠っぽい挙動

Posted at

前提

先にこちらの記事の内容を理解しておくことをお勧めします。
https://qiita.com/shiozaki/items/b3aaff926b7b601b4f86

概要

requireオペレーターが書かれたワークフローが失敗した時に、リトライする手順によっては意図せずワークフローを二重に起動することになります。

再現手順

以下のワークフローを用意します。

workflow1.dig
+step1:
  require>: workflow2
workflow2.dig
+step2:
  sh>: exit 1 # this is a bug.

workflow1がworkflow2をrequireしています。
workflow2にはバグ( exit 1 )があり、shオペレーターが失敗します。

この状態で、workflow1を実行させてみます。
workflow1がworkflow2を呼び出しますが、workflow2のstep2で失敗し、連鎖的にworkflow1のstep1が失敗しています。

別のシェルで起動しておく
$ digdag server -m -O /tmp/digdag_log
$ digdag push sample
$ digdag start sample workflow1 --session '2019-01-01 00:00:00'
log
2019-03-24 19:16:03 +0900 [INFO] (XNIO-1 task-19): Starting a new session project id=1 workflow name=workflow1 session_time=2019-01-01T00:00:00+00:00
2019-03-24 19:16:04 +0900 [INFO] (0044@[0:sample]+workflow1+step1): require>: workflow2
2019-03-24 19:16:04 +0900 [INFO] (0044@[0:sample]+workflow1+step1): Starting a new session project id=1 workflow name=workflow2 session_time=2019-01-01T00:00:00+00:00
2019-03-24 19:16:04 +0900 [INFO] (0044@[0:sample]+workflow2+step2): sh>: exit 1
2019-03-24 19:16:04 +0900 [ERROR] (0044@[0:sample]+workflow2+step2): Task failed with unexpected error: Command failed with code 1
java.lang.RuntimeException: Command failed with code 1
    at io.digdag.standards.operator.ShOperatorFactory$ShOperator.runTask(ShOperatorFactory.java:143)
    at io.digdag.util.BaseOperator.run(BaseOperator.java:35)
    at io.digdag.core.agent.OperatorManager.callExecutor(OperatorManager.java:312)
    at io.digdag.core.agent.OperatorManager.runWithWorkspace(OperatorManager.java:254)
    at io.digdag.core.agent.OperatorManager.lambda$runWithHeartbeat$2(OperatorManager.java:137)
    at io.digdag.core.agent.ExtractArchiveWorkspaceManager.withExtractedArchive(ExtractArchiveWorkspaceManager.java:77)
    at io.digdag.core.agent.OperatorManager.runWithHeartbeat(OperatorManager.java:135)
    at io.digdag.core.agent.OperatorManager.run(OperatorManager.java:119)
    at io.digdag.core.agent.MultiThreadAgent.lambda$null$0(MultiThreadAgent.java:127)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
2019-03-24 19:16:04 +0900 [INFO] (0044@[0:sample]+workflow2^failure-alert): type: notify
2019-03-24 19:16:05 +0900 [INFO] (0044@[0:sample]+workflow1+step1): require>: workflow2
2019-03-24 19:16:05 +0900 [ERROR] (0044@[0:sample]+workflow1+step1): Task +workflow1+step1 failed.
Dependent workflow failed. Session id: 2, attempt id: 2
2019-03-24 19:16:06 +0900 [INFO] (0044@[0:sample]+workflow1^failure-alert): type: notify

バグを修正し、digdag pushします。

workflow2.dig(fixed)
+step2:
  sh>: exit 0 # fixed the bug
digdag push sample

次にリトライをしますが、この時に、sessionを見ると2つのセッションがあることが分かります。
セッションが2つあるので、どちらから先にリトライするべきか悩みます。
リトライする順序によっては同じワークフローが二重に実行される恐れがあるので、注意が必要です。
このようなケースの場合は、 requireオペレーターが書かれている側のワークフローだけをリトライすると、2つのワークフローがそれぞれ1回だけ実行されます。

$ digdag sessions
2019-03-24 19:20:27 +0900: Digdag v0.9.33
Sessions:
  session id: 1
  attempt id: 1
  uuid: 11164087-9f57-4ece-85fe-8530d853c9fb
  project: sample
  workflow: workflow1
  session time: 2019-01-01 00:00:00 +0000
  retry attempt name:
  params: {}
  created at: 2019-03-24 19:16:03 +0900
  kill requested: false
  status: error

  session id: 2
  attempt id: 2
  uuid: afef1840-53ab-4181-9380-a13d62ed64f0
  project: sample
  workflow: workflow2
  session time: 2019-01-01 00:00:00 +0000
  retry attempt name:
  params: {}
  created at: 2019-03-24 19:16:04 +0900
  kill requested: false
  status: error

以下、workflow2が二重起動してしまう手順です。
workflow2側のセッションを先にリトライします。(1回目)

$ digdag retry 2 --latest-revision --resume

この時点でセッション一覧を見ると、workflow1側のセッションはfailuerのままです。
ですので、次にそちらのセッションもリトライします。

$ digdag retry 1 --latest-revision --resume

この時、workflow1側は既にsuccessなセッションがあるにもかかわらず、再度実行されてしまいます。(2回目)
なお、この挙動は --resume オプションではなく --all オプションを指定した場合や、web UIのRETRY ALL ボタンや RETRY FAILED ボタンを押した場合も同様です。

まとめ

失敗したrequireをリトライする時にはどちらのワークフローからリトライするかによって挙動が変わる。

requireオペレーターが書かれた側のワークフローをリトライする
→ 引数に指定されたワークフローも連鎖的に起動され、どちらのワークフローも1回ずつ実行される

requireオペレーターの引数に指定された側のワークフローをリトライし、その後にrequireオペレーターが書かれた側のワークフローをリトライする
→ requireオペレーターの引数に指定された側のワークフローは2回、requireオペレーターが書かれた側のワークフローは1回実行される

多くのケースでは前者の挙動が望ましいケースになるかと思います。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2