Digdag公式ドキュメントからDigdagを学ぶ-Scheduling workflow

# 目標
Digdagの公式サイトのドキュメントのScheduling workflowの翻訳＋α
DigdagのRubyを使ってRailsにバッチを作るまでが最後の目標
http://docs.digdag.io/scheduling_workflow.html

# 目次
[Getting started](https://qiita.com/amagasu/items/92ad70c33f73ab613d08)
[Architecture](https://qiita.com/amagasu/items/572075dcc8b3c8640072)
[Concepts](https://qiita.com/amagasu/items/c850db3b564a7d6dc99c)
[Workflow definition](https://qiita.com/amagasu/items/2a8b84ac8fb4da2d9968)
[Scheduling workflow](https://qiita.com/amagasu/items/9f47a34884ba06d93264)
[Operators](https://qiita.com/amagasu/items/1f9b26a71c86fc9d4607)
Command reference
[Language API -Ruby](https://qiita.com/amagasu/items/b11527d92d259bd3ab48)
[Digdagで環境毎に設定値を変える（RubyOnRails）](https://qiita.com/HavenSpring/items/bb1c7fbae9175c1f9479)
[Digdagを用いてRubyOnRails環境でバッチ実装](https://qiita.com/HavenSpring/items/b3c3e26ef868f8d5eaf4)

# Scheduling workflow
## **Setting up a schedule**
ワークフローを定期的に実行するには、ワークフロー定義の最初に```schedule：``` オプションを追加します。

簡単なワークフローを生成します。日本時間の毎日9時に実行させる場合以下のようにスケジュールオプションを追加します。

```ruby:workflows.dig
timezone: Asia/Tokyo

schedule:
  daily>: 09:00:00

+step1:
  sh>: echo start schedule ${session_time}
```

Digdagサーバーを起動してworkflowsプロジェクトをDigdagサーバーにプッシュします。
```
$ digdag server --memory
$ cd workflows
$ digdag push workflows
```


ワークフローの詳細を見るとセッションに9時の実行履歴が追加されてStatusはSuccessになっています。
`127.0.0.1:65432`
![スクリーンショット 2020-07-12 9.00.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/3280713f-1d65-491a-6c21-50434ce80227.png)

SessionsのSuccessをクリックすると実際試行情報も確認できます。
![スクリーンショット 2020-07-12 9.08.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/6ba5c3d8-967d-e212-ab47-d8a91e631d97.png)

```schedule:``` オプション

| 構文      |       説明 |    例|
|:-----------------|:------------------|:-----------------|
| hourly>: MM:SS         |毎時 30分に実行| hourly>: 30:00 |
| daily>: HH:MM:SS       |毎時 7時に実行| daily>: 07:00:00|
| weekly>: DDD,HH:MM:SS  |毎週9時に実行| weekly>: Sun,09:00:00|
| monthly>: D,HH:MM:SS   |毎月一日の9時に実行| monthly>: 1,09:00:00|
| minutes_interval>: M   |30分ごとにこのジョブを実行する| minutes_interval>: 30|
| cron>: CRON      |複雑なスケジューリングにはcron形式を使用||


digdag checkコマンドは、最初のスケジュールがいつ開始するかを示します。

```rb:check
$ digdag check
2020-07-12 09:23:10 +0900: Digdag v0.9.41
  System default timezone: Asia/Tokyo

  Definitions (1 workflows):
    workflows (2 tasks)

  Parameters:
    {}

  Schedules (1 entries):
    workflows:
      daily>: "09:00:00"
      first session time: 2020-07-13 00:00:00 +0900
      first scheduled to run at: 2020-07-13 09:00:00 +0900 (in 23h 36m 47s)

```
**注意**

```
hourly、ddaily、weekly、またはmonthly使用する場合、セッション時間は実際の実行時間と異なる場合があります。
セッション時間は、実際の実行日の00:00:00です（hourlyの場合、時間は00:00に設定される）。
```
スケジュール例（システム時間：2019-02-24 14:20:10 +0900）
セッション時間は全て「00:00:00」になっている

| schedule      |     first session time |    first scheduled to run at|
|:-----------------|:------------------|:-----------------|
| hourly>: 32:32         |2019-02-24 14:00:00 +0900| 2019-02-24 14:32:32 +0900|
| daily>: 10:32:32       |2019-02-25 00:00:00 +0900| 2019-02-25 10:32:32 +0900|
| weekly>: 2,10:32:32  |2019-02-26 00:00:00 +0900| 2019-02-26 10:32:32 +0900|
| monthly>: 2,10:32:32  |2019-03-02 00:00:00 +0900| 2019-03-02 10:32:32 +0900|


## **Running scheduler**
```digdag scheduler```はスケジューラを起動します。

```
$ digdag scheduler
```

ワークフロー定義を変更すると、スケジューラはdigdag.digファイルを自動的に再ロードするため、再起動する必要はありません。

以前9時に設定されている時間を12時に変更して```digdag scheduler```を実行してみたがエラーが出ました。
digdagのバグかもと思って調べたら以下のようなISSUEがありました。
schedulerはメンテも活発に行ってなさそうだったので```digdag scheduler```よりは```digdag server```をお勧めします。

```ruby:workflows.dig
timezone: Asia/Tokyo

schedule:
  daily>: 12:00:00

+step1:
  sh>: echo start schedule ${session_time}
```

```ruby
$ digdag scheduler
1) Error injecting constructor, java.lang.IllegalArgumentException: Configured authenticatorClass not found: io.digdag.standards.auth.jwt.JwtAuthenticator
  at io.digdag.server.ServerModule$AuthenticatorProvider.<init>(ServerModule.java:176)
  while locating io.digdag.server.ServerModule$AuthenticatorProvider
  while locating io.digdag.spi.Authenticator
    for the 1st parameter of io.digdag.server.AuthRequestFilter.<init>(AuthRequestFilter.java:28)
  while locating io.digdag.server.AuthRequestFilter
  while locating io.digdag.server.AuthRequestFilter annotated with @com.google.inject.internal.UniqueAnnotations$Internal(value=3)
1) Error injecting constructor, java.lang.IllegalArgumentException: Configured authenticatorClass not found: io.digdag.standards.auth.jwt.JwtAuthenticator
  at io.digdag.server.ServerModule$AuthenticatorProvider.<init>(ServerModule.java:176)
  while locating io.digdag.server.ServerModule$AuthenticatorProvider
  while locating io.digdag.spi.Authenticator
    for the 1st parameter of io.digdag.server.AuthRequestFilter.<init>(AuthRequestFilter.java:28)
  while locating io.digdag.server.AuthRequestFilter
  while locating io.digdag.server.AuthRequestFilter annotated with @com.google.inject.internal.UniqueAnnotations$Internal(value=3)

```
## **Checking scheduling status**
クライアントモードのコマンドを使用して、スケジュールを管理できます。
クライアントモードのコマンドについては今後整理します。早めにみたい方は以下のリンク参照
http://docs.digdag.io/command_reference.html#client-mode-commands

スケジューラコマンドは、デフォルトで```http://127.0.0.1:65432```をリスンします。 127.0.0.1（localhost）からの接続のみ受け付けます。これはセキュリティ上の理由から、パブリックネットワークへのポートは開かれません。
リスンアドレスを変更するには、-bind ADDRESSオプションを使用してください。

## **Setting an alert if a workflow doesn’t finish within expected time**
例がなかったので簡単なコードで確認します。
ワークフローの実行時間が1秒以上かかる場合、警告を表示

```ruby:workflows.dig
timezone: Asia/Tokyo

schedule:
  daily>: 11:45:00
sla:
  duration: 00:00:01
  +notice:
    sh>: echo alert! so slow

+step1:
  sh>: ./your_script.sh
```

```sleep 5```にして5秒遅延させる

```shell:your_script.sh
#!/bin/bash
sleep 5
echo start script
```

サーバーのLogをみたい場合、起動の時にtask-logオプションを追加してください。

```
$digdag server --memory --task-log ./task_log

1秒で設定したワークフローの実行時間がが5秒かかったのでLogにaletメッサージが表示されています.
StatusはSuccessになっています。

```
![スクリーンショット 2020-07-12 11.46.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/42df987f-6d8c-5684-da9f-ba420cfb9a1e.png)



## **Options**
このパラメーターは、```fail：BOOLEAN```および```alert：BOOLEAN```オプションをサポートしています。 
```c```を設定すると、ワークフローが失敗します。
```alert：true```は、上記の通知メカニズムを使用して通知を送信します。

```
fail：trueを設定すると、ワークフローが失敗します。
alert：trueを設定すると、上記の通知メカニズムを使用して通知を送信します。上記の例では時間が過ぎてもStatusがSuccessになっていたのはこの設定がDefaultだと思います。
```

```fail:true``` を追加してみると実行時間が1秒超えた場合StatusがFailureになるのがわかる。

```rb:add_fail_option
timezone: Asia/Tokyo

schedule:
  daily>: 12:03:00
sla:
  duration: 00:00:01
  fail: true
  +notice:
    sh>: echo alert! so slow

+step1:
  sh>: ./your_script.sh
```
![スクリーンショット 2020-07-12 12.05.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/2660f832-c0bc-9905-7b6c-64c6a8aedb6f.png)


## **Skipping a next workflow session**
セッション間の継続時間よりも長い時間がかかるワークフロー（30分または60分ごとのセッションなど）を頻繁に実行している場合があります。
ワークフローの期間におけるこの変動は、いくつかの理由で発生する可能性があります。たとえば、通常処理しているデータの量が増加している場合が該当します。

たとえば、1時間ごとに実行されるワークフローがあり、通常30分しかかからないとします。しかし、これは休日であり、現在はサイトの使用率が大幅に増加した結果ワークフローで1時間30分かかっている大量のデータが処理されています。
この期間中、2番目のワークフローが次の1時間実行開始されます。両方が同時に実行されるため、使用可能なリソースにさらに負担がかかります。

この場合は、次の1時間のワークフローセッションをスキップし、代わりに後続のセッションを利用して2時間のデータを処理するのが最善です。これを行うために、以下を追加しました。

```skip_on_overtime：true | false```: セッションが既に実行されている場合にスケジュールされたセッションの実行をスキップするかどうかを制御するために使用

スケジュールされたワークフローセッションには、以前に実行されたセッション時間を含む```last_executed_session_time```変数があります。通常```last_session_time```と同じです。```skip_on_overtime：true```が設定されている場合か```セッションが最初の実行```である場合は値が異なります。

毎分実行されるワークフローを定義

```rb:workflows.dig
timezone: Asia/Tokyo

schedule:
  minutes_interval>: 1
  skip_on_overtime: true
+step1:
  sh>: ./your_script.sh
```

```rb:your_script.sh
#!/bin/bash
sleep 120
echo start script
```

毎分実行予約しても実際スクリプトは2分かかるサンプルです。
```skip_on_overtime: true```により1分ごとに実行設定しても実際は最初の実行が終わった後の1分後に次の実行時間が決まります。
![スクリーンショット 2020-07-12 12.33.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/22feddc3-65bf-9142-6f10-a69e107b0780.png)

## **Skipping backfill**

```skip_delayed_by``` オプションを使用すると```backfill``` コマンドで、指定した時間だけ遅延したセッションの作成をスキップできます。 

Digdagが再起動すると、スケジュールのセッションが、last_session_timeの次のセッションまで自動的に作成されます。

```
schedule:
  minutes_interval>: 1
  skip_delayed_by: 3m

+setup:
  sh>: echo ${session_time}
```

スケジュール停止の時
![スクリーンショット 2020-07-12 13.16.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/d11954b1-14e2-a4a9-f907-5d9163894e15.png)

スケジュール再開の時（17分に再開）
![スクリーンショット 2020-07-12 13.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/50df8228-91e5-e455-70c9-74320978be10.png)
再開時間の3分前の14分、15分、16分は再実行される、3分以上過ぎたセッションはSkipしている。