人事システム「COMPANY」のバッチ処理の裏(側) の話

## この記事は

[Develop fun!を体現する Works Human Intelligence Advent Calendar 2020](https://qiita.com/advent-calendar/2020/whi)
[Develop fun!を体現する Works Human Intelligence #2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/whi-2)
Works Human Intelligence アドベントカレンダー 12/5 の記事です。
今年も[本家 本番環境でやらかしちゃった人は大賑わいですね！](https://qiita.com/advent-calendar/2020/yarakashi-production) 当記事はワークスHI版やらかしちゃった話のひとつだったりしたりしなかったり（略）ですがさておいて。どうぞ少しだけ、日本の名だたる有名法人をお客様に据える「大手法人向けERP」っぽさを感じていただけたらなと思います。


## 大手法人向け統合人事システム「COMPANY」の「リモートジョブ」
いわゆる「ERP」パッケージソフト「COMPANY」を開発している我々ですが、オンライン処理・バッチ処理で分けた場合のバッチ処理を行う基盤をおよそ弊プロダクトではそう呼んでいます。まず一般論としてのバッチ処理は [バッチ処理について考える](https://qiita.com/koduki/items/e90ee1fea5aa75071d95) がわかりやすいです。今日は我々の若きトラブル談を中心に書きます。


## まずざっくりと中身は 

- クライアント：フロントエンド
アプリケーションサーバ（以下AP）：フロントエンドからの依頼をどうのこうの処理して画面に即返したり、主に人間の待てる範囲の非同期処理をしたりする。
- キュー管理サービス：アプリケーションサーバの行っていた処理のうち、主に人間が待てない範囲の非同期処理依頼の、順番、実行、実行履歴を管理する。
- Kicker：サービスに依頼された処理を、依頼されたとおりに実行する。
- 業務処理：処理そのもの。従業員を雇用したり、異動させたりからお給料を計算したり明細を発行したり。

という感じ。以上登場人物。


## 担う業務で分けると

業務と言っていますが「ドメイン」の概念に近いかもしれません。

- 新入社員の個人情報を登録する
- 異動する従業員の属性を変更する
- 入社予定の社員の情報を一括登録する
- 社員の給与計算業務を夜間に行う
- 勤怠時間の計算情報を受けとる
- 計算結果を帳票として他所に送るために出力する

等等々なことをしたい場合に使われるバッチ。調べると1000本以上種類があります。


## 本題

弊社の旗艦プロダクト[COMPANY](https://www.works-hi.co.jp/products/hcm)は現在Ver.8を絶賛提供中。なのですが時代はVer.5, Ver.6に遡ると20余年をゆうに超えるご長寿プロダクトです。私は2003年新卒で入社したのでそこそこ自らの時代を共にしています。

### 「リモートジョブ」のトラブルを語りたい

弊社へのお問い合わせトップ5には軽く入ると思われる

1. バッチが異常終了する
1. バッチが処理中のままいつまでも終わらない
1. バッチが処理待ちのままいつまでも始まらない

というのがバッチ3大トラブルです。始まらない&終わらない、アベンドするってまともに動いてないじゃないかと思われそうですがごにょごにょ


## シーケンス図

細かく見ていきましょう。おしゃれに描くとこういう感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/946dcefb-d9b7-7bcc-f259-6d9c0800c62b.png)

### なのですがちょっと待って下さい
最初の図に少し偽りがあったので訂正します。そうです。キュー管理サービスはAP（アプリケーションサーバ）内のただの1インスタンスだったのです。と思って見るとなんだかいっぱいお仕事名が書いてありますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/6de9a219-4ae2-5842-1e44-e53aba7efdc9.png)
(中略)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/f8f7305e-7bf2-9ac1-8c75-301c4a39dbe4.png)

うわっ、APの役割多すぎ。。。？
さて何が起こるか見ていきましょう。

#### 異常終了

どストレートに。バッチが異常終了します。図では一番右の線上で起こります。原因はバッチ自身であることが多いと信じて、今回は割愛。

#### 処理中

ぱっと思いつく事案として、ほぼ、業務処理が走ったまま息絶えているケース。

- ファイルが見つからなかった（ファイル転送などなどはうまく行ったはずなのに別の階層を見てるとか
- Exeが見つからなかった（何かの作業中リネームされてたとかいうこともあった
- Javaの実行環境のなにがしかのトラブル。他のアプリ様と同居しているせいでバージョンがよろしくないとか
- 途中でDBやAPに異常が起こって処理は落ちてるがいわゆるKickerさんの方でそれを検知できてない
- 複数ジョブを並列利用する式の処理で親ジョブが子ジョブを蹴ったがそれを見失って親ジョブずっと処理中

等など。例えば処理中になったときでも

- キャンセル
- 一時停止と再開

がせめてできたら怒られないんじゃないかな。（客観視）

#### 処理待ち

もっとも語りたいのがこれ。まずそのジョブがファイル転送を伴うジョブかそうでないかが関わります。ファイル転送を伴い特にファイルを取り込むジョブは

1. キューに投入
2. ファイルを転送
3. ジョブをスタートさせる

3段階で命令を出す必要があるのですが処理待ちはつまり1,あるいは2までの状態。
特に2がコケて開始命令を遅れていないがよくあるパターンです。その場合は各サブシステム担当にもっかい確認をお願いしたりサブシステム側に潔白を主張されたときにはExe名を聞いて[Delphi](https://qiita.com/e99h2121/items/e5b823ae69ce418ea235) ソース落としてきてはじめましてながらそのサブシステムから読み始めるとかもやります。そこまでやるのが「リモートジョブ担当」、と思うほどまでは責任感はないですがたまにそのくらいしないと判明しないトラブルが起こります。

それでも判明しないことがたまにあってクライアントからFTPつながってますかとかたまにコケるという話のときは酷いと[Wiresharkとってみてください](https://qiita.com/e99h2121/items/7e7da79c7af6235fe762) とか言ったこともある気がします。

だけじゃない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/4e4bf6b2-5d8a-e3e8-4ac4-30632c05dd37.png)

というかこれも「APでキュー管理サービスが動いている」話の伏線回収！
とりわけAPが複数台ある場合。さあ盛り上がってきそうですね。

APが複数台ある場合でも、キューの制御を行うのはお一つで良いわけなので「主」APを決めないといけません。でもジョブが走り出した後で主が変わってしまったらどうしよう？例えばちょっとした「取込インターフェース」が走りだそうとするまさにそのタイミング別のプロセスがまあ大概かの「帳票出力システム」でExcel形式ででかい帳票を出してしまうなど。

両者は全く別のサブの別のものですが[OutOfMemory](https://qiita.com/e99h2121/items/ed9842bc5d1764c9a571) で主サーバが倒れます→キュー管理サービスが別サーバに移る。実はDBのテーブルでAPの主・副は決まっていたんですが切り替え作動後、発行されたトークン的な情報は代替サーバに引き継がれていない。よって走ろうとしたジョブがバッチサーバ内で「ログイン」できない、というかせっかく発行してもらったトークンの持って行き先がない。。→走り出せず処理待ち


## 密です

意図しないところがBlockerになるものなのです。冒頭に書いたオンライン処理とバッチ処理、弊プロダクトには「アイコン」ベースでこれも3800を超える数の機能があります。本当はそれぞれがそれぞれ、動けばよいはず。

しかしいわゆる「3層構造」へ変更を行ったのがはや20年近く前。当時の設計資料を紐解くとJavaを書くことが楽しかったようで今でもそんなソースに出会うとコメントに書かれている紆余曲折の端々がルンルンしています。

アプリケーションサーバが複数台あったときにどれがそれを行うか、負荷分散オッケー、クラスタサイコー、という「横つながり」（と表現するのは少し語弊があるかもしれないが）概念ができた一方、バッチ処理とオンライン処理の役割分担の切り離し方。キュー管理システムをAPに置いてしまったため結局バッチがAP無しでは動けなくなったというのが僕たちの過ちです。

例えば人事帳票１つを出力するにExcelフォーマットで全従業員数千人分なんてワンパクをしてしまいうっかりOOMErrorでも起こればバッチも止まる、APごと再起動してくださーいとなる。
そんな本番環境でやらかしちゃった話の種がここにもひとつ...


## 「というお話だったのサ」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/7cfd9347-99e8-2e12-19f6-3cacc504f3fa.png)

ではなくて、トラブル談だけ書いているとそのうち怒られる心配があるので、以下、それが既にどう解決されているかについて書いておきます。


### 時は変わりVer.7

あれ？APがいつの間にかいらっしゃらない。そうなんです。やっとここで「キュー管理サービス」はめでたく独り立ちできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/015affd1-c4d7-796b-25b3-b7a99b9f1082.png)

だいぶスッキリしましたね！キュー管理サービス間は独自にソケット通信を行い起動停止、バッチ実行の交通整理を行います。


## Ver.8から、今後

### Fargateとかもやってます

各業務がFargate内で独立すれば、より処理中、処理待ちにまつわる懸念点が解消される目論見です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/d95cd70d-fd22-d2cf-69cf-0c49bf5e6c9b.png)

より独立した未来が見えそうです。ということで安心いただけたらと思います。
[バッチサーバーをFargate化しました - Qiita](https://qiita.com/e99h2121/items/cd0dea16b946869e1846)
[バッチサーバーFargate化プロジェクトのまとめ - Qiita](https://qiita.com/e99h2121/items/38cb0e004d51dffd2716)


## 参考文献
[バッチ処理について考える](https://qiita.com/koduki/items/e90ee1fea5aa75071d95)
[Markdownテキストでシーケンス図とフローチャートを描く](https://qiita.com/ka215/items/a709665cb34c505ccf1f)
[Visual Studio Code で UML を描こう！](https://qiita.com/couzie/items/9dedb834c5aff09ea7b2)