digdag kill が実行されてから Attempt が停止するまでの挙動

Written by @ryysud

Sep 23, 2018 01:00 · 1466 words · 3 minutes read #digdag

TL;DR

digdag kill( = WebUI の KILL ボタン押下 )が実行された時点での、実行中 Task が完了したら、それ以降の Task を停止させる仕様となっている。実行中 Task を含め即座に停止させたい場合には Digdag Server に ssh で接続して、該当 Task からプロセスを直接 kill するしか方法がない。

※ v0.9.27 時点での仕様

モチベーション

業務で Digdag を運用していて、実行中の Workflow を停止するオペレーションを実施する際に、WebUI(Workflows -> Sessions -> Attempts)から KILL ボタンを押下する流れで作業を行っているのですが、KILL ボタンを押下して Attempt の State が Canceling となってから即座に停止することなく、停止するまで時間を要するという課題がありました。

KILL ボタンが正常に機能していないことを疑い、Digdag Server に ssh で接続して digdag kill コマンドを実行しても同じような挙動だったので、チーム内で「Digdag の仕様なのかバグなのかよくわからないし、時間が経てば停止するからまあいいか。」という根拠なき落とし所で先述の運用を続けていました。

しかし、そろそろ自分の中で強烈なモヤモヤが止まらなくなってきたので、今回はローカルで Digdag を稼働させて、内部的な挙動を追っていこうと思います!

動作確認する Digdag のバージョン

今回は v0.9.27 を利用して挙動をみていきます

※ 2018年9月18日時点での最新バージョン(ブログを書き上げている間に v0.9.28 がリリースされてた…。)

WebUI の KILL ボタン押下してから Canceling の状態が長い様子

以下のように KILL ボタンを押下して Attempt が Canceling 状態になるものの即座に停止しない
※ 暫く時間が経つと停止する

kill-attempt.png

digdag kill を実行してから Canceling の状態が長い様子

同上…。つまり KILL ボタンか digdag kill コマンドかどうかは関係なく、即座に停止しない。

treasure-data/digdag のソースコードを追っていく

それっぽい処理を見つけた
https://github.com/treasure-data/digdag/blob/master/digdag-core/src/main/java/io/digdag/core/database/DatabaseSessionStoreManager.java#L382-L424

コメントによると、実行中 Task の State 変更による不具合を避けるために、実行中 Task はそのままにして、停止のリクエストは投げない仕様(実行中 Task も後から Canceled になっているぽいけどコードが特定できていない)となっている模様。つまり、digdag kill( = WebUI の KILL ボタン押下 )が実行されると、実行中 Task は走らせたままで、それ以降の Task を停止させる仕様となっている。

Lock all running tasks.

Locking running tasks is necessary to avoid following scenario:
Thread-A: WorkflowExecutor.taskSucceeded or taskFailed
Thread-B: requestCancelAttempt
1. Thread-A locks task1 (lockTaskIfExists).
2. Thread-A checks stateFlags of task1 => not cancel-requested.
3. Thread-B issues UPDATE to set cancel-requested flag to all tasks.This can set cancel-requested flag to some tasks immediately, but updating task1 blocks because it’s locked.
4. Thread-A inserts some generated subtasks: task2.
5. Thread-A unlocks task1.
6. Thread-B continues UPDATE statement. It updates task1. But it
might not update task2 depending on processing order.

ソースコードを踏まえた上で挙動を確認していく

以下の workflow を用意

### sample.dig

timezone: Asia/Tokyo

+first-task:
  echo>: 'Hello, First task!'

+second-task:
  sh>: sleep 60

+third-task:
  echo>: 'Hello, Third task!'

+sample+second-task が開始されたタイミングで WebUI の KILL ボタンを押下してみる

想定通り KILL ボタンを押下しても、Attempt は即座に停止しない。Tasks に注目してみると、+sample+second-task は Running 状態のままで、+sample+third-task は Canceled 状態になっていることがわかる。

canceling-attempt.png

+sample+second-task が完了した時点で、Attempt が Canceled となった。
なお +sample+second-task も完了したものの Canceld 状態となっている。

canceled-attempt.png

ついでに RETRY FAILED を実行した際の挙動も確認しておく。

execute-retry-failed.png

+sample+second-task から実行が始まった。つまり +sample+second-task は2度実行される形となる。

done-retry-failed.png

Attempt が Canceling 状態のときに +sample+second-task のプロセスを kill してみる

KILL ボタンを押下して Canceling 状態を作る。

canceling-attempt-again.png

Digdag Server に ssh で接続して kill [+sample+second-task pid] コマンドで +sample+second-task から実行されているプロセス(今回でいうと sleep 30 のプロセス)を落とすと、+sample+second-task は Failure でなく Canceled となった。

canceled-attempt-again.png

まとめ

TL;DR がまとめ的な役割です。digdag kill の仕様を理解することが出来たので、また少しだけ Digdag と仲良くなれた気がします。今後もナレッジを増やしていけるようにがんばります。