JS7® JobScheduler 並列処理をまたぐJob連携

# 概要

Workflowにて、並列処理をまたいでJobの実行順序を調整する手段について説明します。
NoticeBoardを使うことで、通常のFork処理では実現できない処理の連携を行います。

# 前提条件

- JS7 jobscheduler の環境準備、初期設定を済ませていること。
  サンプルWorkflowを使ってざっと学習していることが望ましい。
  まだの方はこちらから
  [JS7® JobScheduler 初期設定、サンプルWorkFlowの登録](https://qiita.com/saitamanokusa/items/2d3162b688329f5ecae2)
- WorkFlowの作成、実行、ログ確認などの基本操作ができること。
  こちらで簡単な操作説明をしています
  [JS7 JobScheduler 初めてのWorkFlow実行](https://qiita.com/saitamanokusa/items/1e5ab48cd2e9d38e035c)
- 本記事はJobScheduler Ver. 2.4.1 で確認した内容です。
今後内容が変わる可能性があります。

# はじめに

本記事では、下図のような条件のWorkflowを定義します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/fe81c43b-2a29-91d2-638c-89b2196d3eea.png)
条件１：　job1系(1a,1b)とjob2系(2a,2b) は並列で実行
条件２：　job2bは、job1aとjob2aの両方が完了後に実行

条件１はFork処理での分岐と、順次処理の組み合わせで容易に定義できます。
しかし条件２は、単純にFork処理の機能だけでは定義できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/ba4d9774-6540-3e29-a620-c16dc1a40c6c.png)
※1a,2a の後で分岐を閉じ、再度1b,2bの分岐を書くこともできますが、並列度合いがいまひとつ。<br>(1aの処理が先に終わっても、2aが終了するまで1bが動かない)

そこで本例では、NoticeBoardを利用することで、この処理を実現する方法をご紹介します。

# 設定

## Noticeboardの定義

Practice - Controller - Notice Boards と展開し、新規にNotice Boardを作成します。
名前は`notice_fork_custom_job1`としてください。

値は下記のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/52ef2555-caaf-441d-99a6-f8f8cc99e487.png)

|設定|値|
|-|-|
|Name|notice_fork_custom_job1|
|Notice ID for posting order | `replaceAll($js7OrderId, '^#([0-9]{4}-[0-9]{2}-[0-9]{2}#\w.+?)-.+?$', '$1')` |
|Notice ID for expecting order | `replaceAll($js7OrderId, '^#([0-9]{4}-[0-9]{2}-[0-9]{2}#\w.+?)-.+?$', '$1')` |
|End of Life of Notice | 60 Seconds |

## Workflowの定義

Practice - Controller - Workflows より、新規Workflow `fork_custom` を作成します。

### 並列処理の追加

下記のとおり、Fork処理とJobを並べて並列処理を設定して下さい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/33ca347c-e5a5-85fa-cf35-e628969fe20e.png)

fork処理を追加して、2つに分岐 (branch1, branch2 を作成)

***branch 1 側***

|Name/Label|（Shellジョブの）Script|
|-|-|
|job1a| `sleep 10`|
|job1b| `sleep 5` |

***branch 2 側***

|Name/Label|（Shellジョブの）Script|
|-|-|
|job2a| `sleep 1`|
|job2b| `sleep 10` |

### PostNocices/ExpectNocicesの追加

次に、job1a の後ろに、PostNotices処理を追加します。
Notice Board には、先ほど作った`notice_fork_custom_job1`を選んでください。
※`notice_fork_custom_job1`に通知を出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/77088ef3-8664-3936-29fc-f2ac42bde0b9.png)

続いて、job2a の後ろに、ExpectNotices処理を追加します。
Notice Board には、先ほど作った`notice_fork_custom_job1`を選んでください。
※`notice_fork_custom_job1`の通知を待ちます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/abe7bfd6-168c-c4c0-bf3c-7469fa19611b.png)

終わりましたら、Deployしてください。

## Workflowの動作確認

定義したWorkflow `/Practice/fork_custom` を実行します。
各Jobの開始、終了時間を確認し、意図した順序でjobが実行されたことを確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/f77fc9fb-6f0e-8a78-7676-203ba8ea3a1d.png)

|時刻|動作|
|-|-|
|19:34:42|workflow 開始|
|19:34:44|job1a、job2a が開始|
|19:34:45|job2a が終了 (job2bはまだ開始されない)|
|19:34:54|job1a が終了|
|19:34:55|job1b が開始（job1a終了直後に開始される）<br />job2b が開始 (job1a,job2a の両方が終了した直後に開始される)|
|19:35:00|job1b が終了|
|19:35:05|job2b が終了 (job1aの終了を待機した影響でjob2系が後に終わる)<br />workflow 終了|

:::note
各Jobのsleep時間を適当に調整し、想定通りの順序で動くか確認してみてください。
:::

## NoticeBoardの動作確認

RESOURCES - Notice Boards より、通知の内容を確認することが可能です。

job2a終了後、ExpectNotice処理が実行されると、NoticeBoard の設定に応じたIDの通知待ちとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/d9c88b3b-2b04-c331-a68e-d5712893cdb1.png)

job1a終了後、PostNotice処理が実行されると、NoticeBoard の設定に応じたIDの通知が届きます。
また、Expectは該当IDの通知を受けたため、消えます。（後続のJob2bが開始されます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/599f990f-9493-c2a5-430d-3deb84cc0c8e.png)

End Of Life で設定した時間経過後、IDは自動的に削除されることを確認してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529537/77c96975-5ee7-c95c-8919-0fb48eca20c7.png)

:::note warn
もしPost/Expect の連携がうまく動作しない場合は、このNotice Id が一致するように、NoticeBoardの設定を調整してください。
:::

:::note
もし通知情報が残ったままの場合は、下記の操作で削除できます。

Post Notice の指定時間が長すぎて残ったままの場合
→ 上記メニュー上より `Delete Notice` の操作
Expect Notice を消したい場合
→ 該当Workflowで ExpectNoticeで待ち状態となっているOrderをCancelで終了
:::

# 【参考】NoticeBoardでの厳密なID指定

NoticeBoardで指定するNotice IDについて、デフォルトで２パターンが用意されています。

- Matching Daily Plan Dates<br>OrderId の日付部分 （`#2022-11-08#T90515128805-root` → `2022-11-08`）
- Matching Daily Plan Dates and Order Name<br>OrderIdの日付＋OrderName  （`#2022-11-08#T90515128805-root` → `2022-11-08root`）

しかし、この2つの設定は、下記の問題があります。

- どちらのケースとも、当日中に何回実行しても、同じ Notice ID となってしまいます。<br>そのため、同日に複数回実行する場合には不向きです。
- OrderIdの日付部分は、手動Orderの場合、UTC日付、DailyPlanによるOrderの場合はJST（指定TimeZone）日付が入ります。<br>そのため手動実行の可能性がある場合、これらの設定はお勧めしません。
- 本記事のようにFork処理内でPostNotice,ExpectNoticeを使った場合、OrderName部分にはBranch名が含まれます。<br>そのため、同一Workflow内であっても、OrderIdやOrderNameは合致しません。
  - PostNoticeでのOrderIdの例：   `#2022-11-08#T90515128805-root|branch2`
  - ExpectNoticeでのOrderIdの例： `#2022-11-08#T90515128805-root|branch1`

そこで本記事では、Notice ID の取得に `replaceAll($js7OrderId, '^#([0-9]{4}-[0-9]{2}-[0-9]{2}#\w.+?)-.+?$', '$1')` と指定しています。
この場合、OrderNameより前の箇所 `2022-11-08#T90515128805`を取得でき、Order単位で一致させることができます。

:::note
厳密さにこだわらないならば、 post, expect ともに 適当な文字列（例えば `'id'` ）でも、通知は可能です。※文字列はシングルクォートで囲う
:::

# 【参考】End of Life of Notice について

End of Life of Notice は、処理内容に応じて適度な時間を指定してください。
例えば本記事の例では、`End of Life of Notice`を1分指定で、仮にjob2aの処理時間に3分かかった場合、job2aの終了を待つ間に、通知が消えてしまいます。
また長すぎれば、期限切れまで通知が残り続けます。

# 【参考】複数処理の連携について

PostNotices, ExpectNotices とも、複数のNoticeBoardを指定できます。
またExpectNotices では、下記のように AND, OR の条件指定が可能です。

- `'notice_job_A' && 'notice_job_B'`  job_A, job_B 両方の通知を受けた場合
- `'notice_job_A' || 'notice_job_B'`  job_A, job_B どちらかの通知を受けた場合
- `( 'notice_job_A' && 'notice_job_B' ) || 'notice_job_C'`  job_A, job_B の両方、または job_C 通知を受けた場合

これを使えば、さらに複数の分岐処理間の連携にも対応できます。

# 最後に

通常のNoticeBoardの使い方だと、複数Workflow間での連携処理を思い浮かべますが、本記事のように、同一Workflow内での使い方をマスターすれば、より柔軟なWorkflowを定義が実現できそうです。

# 参考

[JS7 - Notice Boards](https://kb.sos-berlin.com/display/JS7/JS7+-+Notice+Boards)
[JS7 - PostNotices Instruction](https://kb.sos-berlin.com/display/JS7/JS7+-+PostNotices+Instruction)
[JS7 - ExpectNotices Instruction](https://kb.sos-berlin.com/display/JS7/JS7+-+ExpectNotices+Instruction)
[JS7 - Expressions for Variables](https://kb.sos-berlin.com/display/JS7/JS7+-+Expressions+for+Variables)