digdagメモ

# このページは？

digdagを使うにあたって必要になって調べたことのメモです。
なので網羅的な資料ではなく、偏った資料となる予定。
現在進行形で書いていきます。(2019/4/2更新)

# 最初にすること

初めて使う人は`digdag selfupdate`すると良い。
slack通知をする時バージョンが古くて使えないdigdag変数とかあったので、とりあえず最新化するのがおすすめ。

# 複数の配列を同じindexで要素取得したい

```digdag:公式の例だと二重ループ
+repeat:
  for_each>:
    fruit: [apple, orange]
    verb: [eat, throw]
  _do:
    echo>: ${verb} ${fruit}

# <実行結果の出力>
# 2019-03-29 19:02:03 +0900 [INFO] (0017@[0:default]+main-digdag+repeat^sub+for-0=fruit=0=apple&1=verb=0=eat): echo>: eat apple
# eat apple
# 2019-03-29 19:02:03 +0900 [INFO] (0017@[0:default]+main-digdag+repeat^sub+for-0=fruit=0=apple&1=verb=1=throw): echo>: throw apple
# throw apple
# 2019-03-29 19:02:03 +0900 [INFO] (0017@[0:default]+main-digdag+repeat^sub+for-0=fruit=1=orange&1=verb=0=eat): echo>: eat orange
# eat orange
# 2019-03-29 19:02:03 +0900 [INFO] (0017@[0:default]+main-digdag+repeat^sub+for-0=fruit=1=orange&1=verb=1=throw): echo>: throw orange
# throw orange
```
`eat apple`, `throw orange`の組み合わせが欲しい場合は`loop`を使う。

```digdag
+looooop:
  _export:
    fruit: [apple, orange]
    verb: [eat, throw]
  loop>: ${fruit.length}
  _do:
    +worker:
      echo>: ${verb[i]} ${fruit[i]}

# <実行結果の出力>
# 2019-03-29 19:10:21 +0900 [INFO] (0017@[0:default]+main-digdag+looooop^sub+loop-0+worker): echo>: eat apple
# eat apple
# 2019-03-29 19:10:21 +0900 [INFO] (0017@[0:default]+main-digdag+looooop^sub+loop-1+worker): echo>: throw orange
# throw orange
```

しかし、List[Hash]の方が健全である事に気付くべきだった。

```digdag
_export:
  data: [{"fruit":"apple", "verb":"eat"}, {"fruit":"orange", "verb":"throw"} ]
+looooop:
  for_each>:
    row: ${data}
  _do:
    +worker:
      echo>: ${row.verb} ${row.fruit} 
```

# 変数の定義方法

### exportで定義

```digdag:exportで直接定義
_export:
  foo: 1

+direct:
  echo>: ${foo}
```

```digdag:外部ファイルで定義
_export:
  # !incudeとコロンの間には半角スペースが必要！！
  # digファイルもincludeすることが可能だが、変数のみならymlとして定義したほうが良い。
  # サーバーモードでdigdag pushする時もymlだとworkflowファイルと間違われずに済む。
  !include : conf/param.yml
  # 変数の下に宣言することも可能
  p2:
    !include : conf/param.yml

+yml_root:
  echo>: ${root1}
+yml_hash:
  echo>: ${ha.key1}

+yml_root2:
  echo>: ${p2.root1}
+yml_hash2:
  echo>: ${p2.ha.key1}

# -----------------------------------
# conf/param.yml の内容
root1: 100
ha:
  key1: 201
```

### Python,RubyのAPI利用

```python
import digdag

class MyWorkflow(object):
  def prepare(self):
    digdag.env.store({"my_param": 2})

  def analyze(self, my_var):
    print("my_var should be 2: %d" % my_var)
```

### 実行時にパラメータ定義

```bash
digdag run -p my_var1=foo -p my_var2=abc
```

CodeAsなミドルウェアなのに、実行時にパラメータ設定するのはどうなのだろう？
個人的には実装途中の動作確認などで使うだけにしておいた方が良いと思う。

# 失敗と再実行

digdagにはworkflow中で失敗したタスクだけをやり直す機能がある。
`digdag run main-digdag.dig`を実行すると`.digdag`フォルダが作られる。

```
root@9d86773c89eb:/home/digdag/digdag# find . 
.
./.digdag
./.digdag/plugins
./.digdag/plugins/...省略...
./.digdag/status
./.digdag/status/20190329T000000+0900
./.digdag/status/20190329T000000+0900/+main-digdag+looooop.yml
./.digdag/status/20190329T000000+0900/+main-digdag+looooop^sub+loop-0+worker.yml
./.digdag/status/20190329T000000+0900/+main-digdag+looooop^sub+loop-0.yml
./.digdag/status/20190329T000000+0900/+main-digdag+looooop^sub+loop-1+worker.yml
./.digdag/status/20190329T000000+0900/+main-digdag+looooop^sub+loop-1.yml
./.digdag/status/20190329T000000+0900/+main-digdag+looooop^sub.yml
./.digdag/status/20190329T000000+0900/+main-digdag.yml
./main-digdag.dig
```

`.digdag/status/`の中には`${session_time}/${digファイル名(workflow名)}${task_name}`で**成功したタスク**の実行結果がある。これが無いタスクは失敗を意味し、もう一度同じ`${session_time}`で実行すれば、失敗したタスクだけが実行できる。($session_timeは後程説明する)

例えば上の状態は全て成功しているので、再実行をしてもタスクが全てskipされる。(黄色文字でSkippedと書いてある行のタスク名を見ると良い)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/11203/b69ecdf4-aaf5-53e2-b173-64ecc5b82724.png)

この状態から`loop-0`の結果ファイルを削除し失敗の状態にしてから再実行すると、`loop-0`は再実行され、その他はskipする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/11203/4d0d8a61-1f92-b912-cb15-a03c11828f1d.png)


# session_timeについて

※更新予定

# secretのJSONはネストしてはダメだった

```json:mysql_auth.json
{
  "mysql" : {
    "user" : "root",
    "pass" : "pass"
  }
}
```
```bash
root@a2b9c4624e60:/home/digdag/digdag# digdag secrets --project main-digdag --set @config/mysql_auth.json
2019-04-01 16:04:08 +0900: Digdag v0.9.3
error: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: sun.nio.ch.ChannelInputStream@525575; line: 2, column: 15] (through reference chain: java.util.LinkedHashMap["mysql"]) (json mapping)
```

prefixが重複するが、このように書く。

```json:mysql_auth.json
{
  "mysql.user" : "root",
  "mysql.pass" : "pass"
}
```

```bash
root@a2b9c4624e60:/home/digdag/digdag# digdag secrets --project main-digdag --set @config/mysql_auth.json
2019-04-01 16:06:09 +0900: Digdag v0.9.3
Secret 'mysql.user' set
Secret 'mysql.password' set
```


# server起動でsecretを使う方法


```properties:config/digdag-server.properties
# digdagサーバーの起動時パラメータ

# WebUIを外部から見えるようにするためのIP許可設定
server.bind = 0.0.0.0
server.port = 65432
server.admin.bind = 0.0.0.0
server.admin.port = 65433
server.access-log.pattern = json

# タスクの成功/失敗を記録するためのDB設定
database.type = postgresql
database.user = root
database.password = root
database.host = digdag_db
database.port = 5432
database.database = digdag

# 秘密情報の設定
digdag.secret-encryption-key = MDEyMzQ1Njc4OTAxMjM0NQ==
# 下記は0.9.3で削除されている設定だったので不要 ※コメント参照
# digdag.secret-access-policy-file = /home/digdag/config/secret-access-policy.yml
```

```yml:config/secret-access-policiy.yml
# いらない子なので全てコメントアウト。記事の履歴として残してあるだけ。
# shコマンドでmysql.xxxxというパラメータを秘密情報にする設定
#operators:
#  sh:
#    secrets:
#      - mysql.*
```

```digdag:main-digdag.dig
# 実行内容
# verv, fruitは公開されても良い情報。mysql.userは非公開な情報
timezone: Asia/Tokyo
+looooop:
  _export:
    fruit: [apple, orange]
    verb: [eat, throw]
  loop>: ${fruit.length}
  _do:
    +worker:
      sh>: echo ${verb[i]} ${fruit[i]} ${secret:mysql.user}
```



```bash
# digdagサーバー起動
root@09b806647e98:/home/digdag# digdag server --config config/digdag-server.properties

# secretの登録（今回はMySQLのログイン情報)
root@a2b9c4624e60:/home/digdag# digdag secrets --project abc --set @config/mysql_auth.json
2019-04-01 16:06:09 +0900: Digdag v0.9.3
Secret 'mysql.user' set
Secret 'mysql.password' set

# digdagサーバーにworkflowを登録
root@09b806647e98:/home/digdag# digdag push abc
2019-04-01 16:29:04 +0900: Digdag v0.9.3
Creating .digdag/tmp/archive-1546599854899119290.tar.gz...
  Archiving config/digdag-server.properties
  Archiving config/mysql_auth.yml
  Archiving config/secret-access-policy.yml
  Archiving main-digdag.dig
Uploaded:
  id: 1
  name: abc
  revision: 68eec3aa-8432-40ef-a7c3-a229b754edc6
  archive type: db
  project created at: 2019-04-01T07:25:09Z
  revision updated at: 2019-04-01T07:29:05Z

# workflowの起動
root@09b806647e98:/home/digdag# digdag start abc main-digdag --session now
2019-04-01 16:29:07 +0900: Digdag v0.9.3
Started a session attempt:
  session id: 2
  attempt id: 2
  uuid: ba7d920e-4b7b-466a-94f0-ec81acb69cb3
  project: abc
  workflow: main-digdag
  session time: 2019-04-01 16:29:07 +0900
  retry attempt name:
  params: {}
  created at: 2019-04-01 16:29:08 +0900
```

```text:digdag_start_のログ
2019-04-01 16:29:08 +0900 [INFO] (XNIO-1 task-44): Starting a new session project id=1 workflow name=main-digdag session_time=2019-04-01T16:29:07+09:00
2019-04-01 16:29:08 +0900 [INFO] (0214@+main-digdag+looooop): loop>: 2
2019-04-01 16:29:08 +0900 [INFO] (0214@+main-digdag+looooop^sub+loop-0+worker): sh>: echo eat apple ${secret:mysql.user}
eat apple root
2019-04-01 16:29:09 +0900 [INFO] (0214@+main-digdag+looooop^sub+loop-1+worker): sh>: echo throw orange ${secret:mysql.user}
throw orange root
```

~~`${secret:mysql.user}`が標準出力で表示されないことが確認できた。~~
いや出来てない。ばっちり表示されてる。なんだこれ？

# serverモードのproject削除

```bash
[root@9f7f7798e419 hoge]# digdag delete abc
2019-05-23 15:32:01 +0900: Digdag v0.9.35
Project:
  id: 2
  name: abc
  latest revision: 502cbadc-1a55-4beb-b38d-a108690b74d4
  created at: 2019-05-10 19:30:27 +0900
  last updated at: 2019-05-23 15:31:07 +0900
Are you sure you want to delete this project? [y/N]: y
Project 'abc' is deleted.
```

# serverモードでの再実行

```bash
# Usage: digdag retry <attempt-id>
root@9f7f7798e419:/home/digdag/digdag# digdag retry 1 --keep-revision --resume
2019-04-02 14:11:02 +0900: Digdag v0.9.35
Started a session attempt:
  session id: 1
  attempt id: 2
  uuid: 8dc3a069-44a6-407c-b1c5-42ab964bd2f1
  project: abc
  workflow: main-digdag
  session time: 2019-04-02 13:00:00 +0900
  retry attempt name: 2cda3e9e-f93a-4b68-8bd2-319ed08f28a8
  params: {"last_session_time":"2019-04-02T12:00:00+09:00","next_session_time":"2019-04-02T14:00:00+09:00"}
  created at: 2019-04-02 14:11:03 +0900
```

# session-idとattempt-id

- workflowがsession_timeの実行毎に+1して発行される番号がsession_id。この時workflowは成功/失敗の両方の可能性があるが、失敗時のリトライは同session_timeでの実行なのでsession-idは発行されない。
- workflowの新規実行/リトライを含めて+1して発行される番号がattempt-id。

|workflow名|session_time|session-id|attempt-id|結果|メモ|
|:----------|:-----------|:---------|:---------|:---|:---|
|A|2019-04-01 00:00:00|1|1|成功||
|A|2019-04-01 01:00:00|2|2|成功|異なるsession_timeの実行なのでsession-idを+1|
|A|2019-04-01 02:00:00|3|3|失敗||
|A|2019-04-01 02:00:00|3|4|失敗|リトライなのでattempt_idだけ+1|
|A|2019-04-01 02:00:00|3|5|成功|リトライなのでattempt_idだけ+1|
|A|2019-04-01 03:00:00|4|6|成功||
|B|2019-04-01 03:00:00|5|7|成功|同じsession_timeでも違うworkflowなのでsession-idを+1|

# WebUIでLogsを出すために

workflowの実行ログを閲覧するには`task-log`をサーバー起動時に設定する必要がある。これが無いとLogsは空欄になる。

```bash
digdag server --config config/digdag-server.properties --task-log ./task_log
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11203/57489a2d-7777-7b5f-187d-f6a9a5d57cfc.png)