Digdagサーバのworkflow executor・agent

やりたいこと
===========

http://qiita.com/pilot/items/a49e6985f1c18aa37b5c で作成した2台構成のDigdagサーバについて

`digdag server help`で表示される以下のオプションがどういう意味があるか知りたい

```
--disable-executor-loop    disable workflow executor loop
--disable-local-agent      disable local task execution
```

Digdag 0.8.18にて (0.8.22までは同様の結果であることを確認済)

結論
====

1. 即時実行の場合、セッションの開始は当該リクエスト受付号機によって行われる
1. スケジュール実行の場合、セッションの開始はschedulerによって行われる
    1. schedulerを止めるオプションはなさそう
    1. 複数サーバ稼働時、どの号機のschedulerがセッションを開始するかは不定
1. workflow executorは開始されたセッション内のタスクをキューに入れる
    1. disable-executor-loop指定したサーバはworkflow executorが稼働しない
    1. 複数サーバにてworkflow executor稼働時、どの号機のworkflow executorがタスクをキューに入れるかは不定
1. agentはキュー内のタスクを実行する
    1. disable-local-agent指定したサーバはagentが稼働しない
    1. 複数サーバにてagent稼働時、どの号機のagentがタスクを実行するかは不定

やったこと
=========

workflow executor・agentとは
---------------------------

以下を読んだ/視聴した

1. http://docs.digdag.io/internal.html#api-server-agent-workflow-executor-and-schedule-executor
1. https://www.youtube.com/watch?v=OAaFr_CnXvk

workflow executorはタスクをキューに入れる人
agentはキューからタスクを取って実行する人

2台ともdisable-executor-loopにすると
----------------------------------

push後にstart --session now(即時実行)するとそれを受け取った号機に以下のログが出るがその後何も起こらない
workflow executorが居ないのでタスクがキューに入らないからだろう
(ちなみに`--log-level debug`を指定しているのでDEBUGレベルのAPI受付ログも出ている)

```
～ API受付ログ ～
2016-11-01 10:21:53.010 +0900 [INFO] (XNIO-1 task-5): Starting a new session project id=10 workflow name=a session_time=2016-11-01T10:21:51+09:00
```

以下のように数分後の時刻を書いてpush(スケジュール実行)すると

```
schedule:
  daily>: 10:30:00
```

指定時刻に片方の号機に以下のログが出るがその後何も起こらない
どちらの号機に出るかは不定

```
2016-11-01 10:30:00.716 +0900 [INFO] (scheduler-0): Starting a new session project id=11 workflow name=a session_time=2016-11-01T00:00:00+09:00
```

「Start new session」ログを出力する人は
即時実行時は「XNIO」
スケジュール実行時は「scheduler」

http://docs.digdag.io/internal.html#api-server-agent-workflow-executor-and-schedule-executor には「--disable-executor-loop　　disables workflow executor and schedule executor」とあるが、schedulerはdisableにならないように見える

2台ともdisable-local-agentにすると
---------------------------------

まずは先に起動した号機に以下のログがいくつか出た
(セッションが溜まっていたので、それらのタスクをworkflow executorがキューに入れたのだろう)

```
2016-11-01 10:44:02.291 +0900 [DEBUG] (workflow-executor-0): Queuing task of attempt_id=34: id=392 +a+task1
```

しかしその後何も起こらない
agentが居ないのでタスクがキューから取り出されないからだろう

start --session nowするとそれを受け取った号機に以下のログが出るがその後何も起こらない

```
～ API受付ログ ～
2016-11-01 10:50:53.969 +0900 [INFO] (XNIO-1 task-2): Starting a new session project id=14 workflow name=a session_time=2016-11-01T10:50:53+09:00
2016-11-01 10:50:53.992 +0900 [DEBUG] (workflow-executor-0): Queuing task of attempt_id=44: id=412 +a+task1
```

schedule:に1分後の時刻を書いてpushすると
指定時刻に片方の号機に以下のログが出るがその後何も起こらない
どちらの号機に出るかは不定

```
2016-11-01 10:57:00.173 +0900 [INFO] (scheduler-0): Starting a new session project id=17 workflow name=a session_time=2016-11-01T00:00:00+09:00
2016-11-01 10:57:00.196 +0900 [DEBUG] (workflow-executor-0): Queuing task of attempt_id=47: id=418 +a+task1
```

2台とも指定なしにすると
---------------------

両方の号機をほぼ同時に起動した
両方の号機で溜まっていたキューからタスクが取り出され、タスクが実行された
両方の号機でagentが動いたからだろう

また、1つのdigファイルに複数タスクが書いてあった場合、途中まで1号機、以後2号機、となることもある
「1回のattemptは最初から最後まで1サーバ内で実施されるのかな」と思い込んでいたがそんなことはなかった

1ワークフロー(attempt)の各タスクはどの号機で実行されるかは不定ということがわかった(★)

これらのオプションをどう使うか
===========================

実運用時、複数のサーバを以下のように役割分担するのに使うことになりそう

1. API受付＆workflow executorサーバ
    * 冗長化のため2台、それ以上増やす必要はない
    * API受付とworkflow executorを別マシンにする程の負荷は発生しない想定
        * API受付口はインターネットには公開しない(大量アクセス攻撃を受ける可能性があるので)
    * bindアドレスを0.0.0.0指定
    * disable-local-agent指定
2. agent
    * 冗長化のため少なくとも2台、タスクの重たさ/量に応じてさらに増やす
    * bindアドレス指定なし(他マシンからAPI受付しない)
    * disable-executor-loop指定

こうすることで、タスクが重たくなった/量が増えた場合でも、API受付/キュー入れ/スケジューリングはできるはず

agentマシンではschedulerを動かさないとしたいが、今はそういう指定は不可らしい

失敗談
======

先日「数分おき起動」に設定したdigファイルをうっかりpushしたままサーバをしばらく止めていた
すると、サーバ再起動後に溜まっていたスケジュールが一斉に実行されてOutOfMemory連発
API受付もできなくなった(killもdeleteも出来ないので困った)

少なくともdisable-local-agentなサーバは1つは用意しておきたい
そもそもmax-task-threadsも少なめな値を指定しておくべきだったか

0.9.0から追加になった`skip_on_overtime`を使うといいのかも(未確認)
http://docs.digdag.io/releases/release-0.9.0.html#workflow-changes


NFSの必要性
==========

★について、以下の理由により、Digdagサーバマシン間でNFS等によるファイル共有が必要

＜理由1＞
「とあるタスクでファイル作成後、後続タスクで当該ファイルを参照」とした場合、
ファイル作成タスク実行号機とファイル参照タスク実行号機が異なると、参照時にファイルが見つからない、ということになる
当該ファイルを共有ディレクトリに置くことで解決

→ 関連：[Embulkプラグインを複数Digdagサーバで共有](http://qiita.com/pilot/items/2c4bc45adafa17030f37)

＜理由2＞
タスクログを各号機で別々のディレクトリに出力していると、1号機に対してdigdag logした場合に1号機のタスクログしか取得できない
共通のディレクトリに出力していれば、ある号機に対してdigdag logすると全号機のタスクログが取得できる
「agent稼働サーバとAPI受付サーバは別」にしていても、API受付サーバの起動パラメータ--task-logに共通タスクログ出力ディレクトリを指定しておけば、API受付サーバに対してdigdag logすると全agent稼働サーバのタスクログが取得できる

→ 関連：[digdag logを繰り返し実行するプログラム](http://qiita.com/pilot/items/85bd1e65af6c7fe553c3)

0.9.0から使えるようになったUIでもタスクログが見れるが、そちらもアクセス号機のタスクログしか見れないんだろうか(もう自分の環境をNFSにしちゃったので未確認)

TODO
====

Vagrantfileで複数号機に同じサーバプロセス起動スクリプトを作っているが「1号機ならこのオプション」とか分岐するにはどうするか
http://shim0mura.hatenadiary.jp/entry/2014/02/21/235230 あたりでできるかも
今は「ほとんどの内容が重複する複数のVagrantfile」でやっているがこのままでもまぁいいか