目次

バッチ処理とは?設計のやり方などの基本を解説します【初心者向け】

本サイトはアフィリエイトプログラムを利用した広告を表示しています

バッチ処理を設計することになったとき、具体的なやり方が分からないかもしれません。そもそもバッチ処理とは何か、あいまいになっているかもしれません。私はこれまでウェブサービスやアプリを開発してきて、その中でバッチ処理も設計や実装をしてきました。

この経験を元に、この記事ではバッチ処理とは何か、どう設計すればいいか、そのやり方を解説します。バッチ処理を設計する上で押さえるべきポイントをまとめているので、参考になればと思います。

この記事の対象となる読者の方

この記事はエンジニアとしての実務経験が1〜3年目くらいの方を想定して書いています。また、ソフトウェアの種類としてはウェブアプリケーションやモバイルアプリを想定しています。

著者
Hiroki Zenigami

テクニカルライター。元エンジニア。共著で「現場で使えるRuby on Rails 5」を書きました。プログラミング教室を作るのが目標です。

スポンサーリンク

バッチ処理とは

バット処理の流れ

まず、この記事におけるバッチ処理の定義について示します。バッチ処理とは「入力があり、その入力を加工し出力するプログラム」をいいます。たとえばデータベースから処理対象となるデータを取得し、データを変更した上で更新するプログラムがバッチ処理にあたります。

この処理はなんらかのトリガーによって起動します。たとえば時間がトリガーとなって起動します。

バッチ処理はプログラムの実行方式のひとつで、まとまった処理を一度に行います。時間がかかる処理や定時処理などに有用で、ビジネス側の要件を満たすために重要な役割をもちます。

バッチ処理が満たすべき要件

次にバッチ処理を設計する上で満たすべき要件を定めます。この記事で示す各ポイントは、次の要件を満たすことを目的とします。

  • ビジネス側の要件を満たすこと
  • 問題をできるだけ起こさないこと
  • 処理の状況を把握できること
  • 異常時にリカバリできること
  • リソースの消費を抑えること

バッチ処理を設計するやり方

上記の要件を満たすために、バッチ処理を設計する上で抑えるべきポイントは次のとおりです。各ポイントごとに書いていきます。

順番項目
1ビジネス側の要件を明確にする
2Dry Runできるようにする
3APIを叩く処理はリトライする
4外的要因に依存しないようにする
5テストコードを書く
6ログを出力する
7コミュニケーションツールに通知する
8冪等性をもたせる
9処理対象を引数で指定できるようにする
10リソースの消費を減らす
スポンサーリンク

1. ビジネス側の要件を明確にする

バッチ処理にはビジネス側の要件があります。いつはじまっていつ終わるのか、どの処理の後にはじめるのか。処理対象はなにか。どういう処理をし、どう出力するのか。こういった要件を明確にした上で設計に入ります。

2. Dry Runできるようにする

バッチ処理を実行する際のオペレーションミスを防ぐため、Dry Runの仕組みをとりいれます。バッチ処理はビジネス上重要な処理であることが多いです。処理対象を間違えるとリカバリをする必要があります。

場合によってはメンテナンスモードに入ることになります。これはユーザーのUXを低下させてしまいます。このような問題を防ぐため、処理を実行する前にふるまいをチェックする仕組みをつくります。

正しい処理対象に正しい処理が行えるか。これを標準出力をとおして確認できるようにします。より安全な運用をするために、バッチ処理のデフォルトのふるまいをDry Runにすることも検討します。

3. APIを叩く処理はリトライする

APIの利用制限にひっかかるとバッチ処理全体が失敗してしまいます。これを防ぐため、APIを叩く処理はリトライするようにします。APIによってはRate Limitなどのリクエストに関する制限があります。あるいはAPIが一時的にダウンしているかもしれません。

リトライを行うことでことで、処理全体が成功する可能性を高めることができます。リトライの時間間隔はExponential Backoffという手法が有用です。

4. 外的要因に依存しないようにする

処理が外的要因に依存すると、それが利用不能になった場合にバッチ処理全体が失敗してしまいます。可能な限り依存しないようにします。たとえばバッチ処理内で運用者にSlackで通知したとします。この通知を同期的に行うと、エラーハンドリングしない限りバッチ処理全体が失敗します。

通知の失敗が許容できるケースでは失敗してもいいようにします。具体的には非同期での実行などの方法をとります。

5. テストコードを書く

バッチ処理も、アプリケーションのコードと同じくテストコードを書きます。このことが問題の防止につながります。

テストコードは処理のふるまいを定義し、テストによって正しくふるまっているかを検証します。これを継続的にテストすることで、バッチ処理の品質を保つことができます。

6. ログを出力する

バッチ処理に問題が発生したとき、その調査やリカバリにログを利用します。このためログはバッチ処理において重要な役割を果たします。

ログを設計する際は5W1Hを意識すると効果的です。バッチ処理をいつ開始したか、いつ終了したか。処理対象はなにか。どういう処理を行ったか、行わなかったか。なぜその対象なのか。どの処理か──これは一意の処理IDをログに付与すると、ログ監視ツールで調査しやすくなります。

また、エラーが発生したときはスタックトレースをログに記録します。

スポンサーリンク

7. コミュニケーションツールに通知する

バッチ処理の状況を把握するために、処理内の主要なポイントでSlackなどのコミュニケーションツールに通知します。これによりバッチ処理が正しく動作していることを確認できます。問題が発生したときにはすぐ気づくことができ、リカバリ作業に移行できます。

この通知はエンジニア以外のメンバーにもわかりやすい形で通知します。こうすることで、ユーザーへのフォローまで含めたリカバリを行うことができます。

8. 冪等性をもたせる

バッチ処理は、何度実行しても一度処理した対象を二重に処理しないようにします。「何度実行しても同じ結果が得られる性質」を冪等性といいます。冪等性をもたせることで、処理が失敗したときに再度処理すれば未処理のもののみ処理にかけることができます。

9. 処理対象を引数で指定できるようにする

未処理のデータを指定して処理にかけられるよう、処理対象を引数で指定できるようにします。バッチ処理が失敗したとき、処理されたものと未処理のものが出てきます。未処理のもののみ再実行できるとリカバリしやすくなります。

これは冪等性をもたせることが難しいバッチ処理に対して特に効果的です。また、Dry Runと組み合わせることも有用です。今後実施予定のバッチ処理を、処理対象を指定した上で事前に確認できるようになります。

10. リソースの消費を減らす

バッチ処理は、その性質上コンピューティングリソースを消費しやすいです。できるだけ消費を減らせるよう、実装上の工夫をします。

たとえばデータベースにある大量のレコードを扱うとき、全件をメモリ上に展開すると多くのリソースを消費してしまいます。この場合、分割して処理することを検討します。

またトランザクションも有用ですが、大量のデータに対するトランザクションはデータベースリソースの消費につながります。適切な粒度で行う必要があります。

おわりに

バッチ処理の設計のやり方のまとめ

以上のポイントを意識してバッチ処理を設計することで、ビジネス側の要件を満たしつつ、問題が起きづらいバッチ処理を運用することができます。問題が起きたときにも対処しやすいため、可能な限りポイントを押さえるようにしたいところです。

あわせて読みたい

著者
Hiroki Zenigami

テクニカルライター。元エンジニア。共著で「現場で使えるRuby on Rails 5」を書きました。プログラミング教室を作るのが目標です。

スポンサーリンク

ブログをはじめよう

技術ブログの始め方を、たくさんの画像で分かりやすく解説しました。これまでブログをやったことがない人でも、エンジニアにとって重要なブログを今日から始められます。

ブログをはじめる