個人的な経験でもバッチ処理で悩まされた事は多いので俺的バッチ処理ベストプラクティスを考える。
考慮不足もあるかもしれないので、もしなんかあればツッコミがほしい感じ。
- その1:できるだけバッチ処理は減らす
- その2:1処理1トランザクションにする
- その3:異常発生時、正常に処理できるものは処理してしまうようにする
- その4:バッチ処理再実行時、未処理データに対してのみ再処理されるようにする
- その5:バッチ処理まるごとリトライできるように「バッチ処理実行を無かったことにできる仕組み」を用意しておく
その1:できるだけバッチ処理は減らす
昔はマシンスペックの問題でオンラインで処理していると追いつかなかった為「リソースが空いている夜の時間帯にまとめて処理する」みたいなのがあったと思うが、今はリソースが潤沢にあるのでそういった理由でのバッチ処理は無くしできる限りオンラインで処理してしまう。
どうしてもバッチ処理でなければならないような処理(ある時間に外部システムへデータ連携する等)についてのみバッチ処理として用意する。
その2:1処理1トランザクションにする
バッチ処理では多数のデータに対して処理を実行していく事が多いと思う。
この時、1処理(1まとまりの処理)を1トランザクションとしてコミットしていくようにする。
理由は、不正データにより処理が失敗した際、正常なデータに対して行われた正常な処理までロールバックされてしまわないようにする為である。
複数処理を1トランザクションとして処理していると、不正な1データのためにその他の正常なデータの処理にまで影響が出てしまう。
「とりあえず正常に処理できる物は処理してしまう」という事ができなくなってしまう。
その3:異常発生時、正常に処理できるものは処理してしまうようにする
その2で記した内容と重複するが、複数のデータに対してバッチ処理で一括で処理を実行している場合、Aデータに対して行われる処理とBデータに対して行われる処理には関連はなく、Bが失敗したからといってAの処理も止める必要はない。
原因を取り除いた後、Bデータだけ再度トライすれば良い。
その為に、「その2」にあるように「1処理1トランザクションにする」にしておき、異常があったデータ以外については正常に処理が完了するようにしておく。
その4:バッチ処理再実行時、未処理データに対してのみ再処理されるようにする
なんらかの異常があってバッチ処理が失敗した時、異常の原因を取り除いた後バッチを手動で再実行する必要がある。
この時、エラーが起きたデータを含む「未処理データ」に対してのみ再処理されるようにする。
もしそうなっておらず「処理済みデータも再度処理してしまう」という造りになっていた場合、再実行前に「処理済みデータ」が対象にならないようにデータをいじったり、再処理されても良いように未処理状態に戻すなど余計な手間がかかり、そのときに二次被害を起こしてしまったりする危険性まである。
その5:バッチ処理まるごとリトライできるように「バッチ処理実行を無かったことにできる仕組み」を用意しておく
実行されてしまったバッチ処理に問題があり誤った内容で処理が実行されてしまったとき、問題を修正したあと、処理済みのものを含めて無かったことにし再実行する必要がある。
行うことは「バッチ処理で生成されたデータを削除」「外部システム連携されたデータ内容のキャンセル」等。
この時「データ削除」を「deleteテーブルへの退避」として実装しておくと、調査の観点からも楽になると思う。
これらの処理を土壇場で手作業でやるのはしんどいので機能として用意しておくと良い。