🐈‍⬛

初めてSpring Batchアプリケーションを触ってつまずいたポイント

2024/12/15に公開

はじめに

はじめまして!ウェルスナビのやましたと申します!
私は新卒でバックエンド開発エンジニアとして入社し、社内業務システムの開発を行っているチームに配属されました。

当チームでは、社内業務システムの開発および定期的なリリース作業を行なっています。
そこで扱っている社内業務システムは仮想サーバー(Amazon EC2)で構築されているため、私はコンテナ化されたシステム(Amazon ECS)のリリース作業を行った経験がありませんでした。

そんな中、バッチ処理が実行されているコンテナ化されたシステムのリリース作業を担当することになりました。各Gitリポジトリ・クラスの責務の違いや処理の流れが分かっていない状態からおおよその全体像を掴み、無事にリリースを行うことができました。

その経験から、つまずいた点やSpring Batchアプリケーションの全体像をお伝えできればと思います。

記事の概要

前提

  • Applicationクラスに@EnableBatchProcessingアノテーションが付加されたSpring Batchアプリケーションを扱う
  • 実行したいロジックが記述されているJavaファイルは外部ライブラリ化されていることを想定

対象者

  • バックエンド開発エンジニア
  • Spring Batchをあまり触ったことがない方
    • 細かい話は簡略化して、なんとなくのイメージを掴むことを目的にしています

用語解説

Spring Batchアプリケーションを扱う中で登場する基本的な用語をまとめました。軽く読み流した後で次章に進むと理解しやすいと思います。

コンテナ技術とは

実行するOSなどの環境差異に関係なくアプリケーションを実行できる方法のことです。
https://aws.amazon.com/jp/what-is/containerization/

Batchとは

大量の反復的なデータジョブを定期的に完了するためにコンピュータが使用する方法です。
https://aws.amazon.com/jp/what-is/batch-processing/
https://spring.io/projects/spring-batch

Jobとは

バッチアプリケーションの一連の処理をまとめた1実行単位のことです。
https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/ja/Ch02_SpringBatchArchitecture.html

ECSとEC2とは

概要 特徴
ECS AWSのコンテナ管理サービス Dockerコンテナのデプロイ、管理、スケールを簡単に行える
EC2 AWSのクラウドコンピューティングサービス 仮想サーバー(インスタンス)を提供している

AWS環境でコンテナ化されたアプリケーションを取り扱う場合には、ECSは便利です[1]
例えばバッチ処理をECSで取り扱う場合、デプロイ時にタスク定義更新のみを行う事で、すでに定期実行されているTaskがあったとしても、そのTaskが実行中であるかどうかを気にせずにリリースすることができます。
これは、新しいタスク定義のリビジョンが作成されても現在実行中のタスクには影響を与えないためです。

https://qiita.com/omo_taku/items/867b0e9c7114b84edee2

ECSのタスクスケジューリング機能とは

EventBridgeスケジューラーを使って、ECSタスク(≒コンテナ)をスケジュール実行できる機能です。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/tasks-scheduled-eventbridge-scheduler.html

つまずいたポイント

私が今回初めて触ったSpring Batchアプリケーションを読み解いていく上で、以下の点につまずきました。
これらのつまずきポイントを認識した上で全体像を確認することで、理解が進みやすくなりました。

1. Gitリポジトリごとに責務が全く異なっていた

私がこれまで扱ってきた社内業務システムは1つの大きなGitリポジトリで完結していました。しかし、私が今回初めて触ったSpring Batchアプリケーションでは業務ロジックのコードが別のGitリポジトリに存在しており、そのコードをjarファイル化して外部ライブラリとして読み込んでいました。
つまり、以下の2つのような形でGitリポジトリが分かれていたのです。

  • Batch処理自体の実行ロジックを記述したGitリポジトリ
  • 業務ロジックを記述したGitリポジトリ(jarファイル化して外部ライブラリとして読み込む)

そして、Gitリポジトリごとの責務の分かれ方を認識できていなかったのでコードを理解することができず、つまずいてしまいました。

2. Gitリポジトリ内の各クラスごとの責務の違いと処理の流れがわからなかった

Gitリポジトリごとの責務の違いが分かっても、その中にある各クラスの処理の流れが掴めなかったのでつまずいてしまいました。
WebアプリケーションのMVCモデルのような形で、大まかなフレームとその流れを掴むことで全体像を理解しやすくなりました。

具体的な構造としては、ApplicationクラスRunnerクラスJobクラスの3つに分けて考えました。

    1. Batch処理自体の実行ロジックを記述したGitリポジトリ
    • 1.1 Applicationクラス
      • 単純にアプリケーションの実行を行うクラス
    • 1.2 Runnerクラス
      • 業務ロジックが記述されている外部ライブラリを呼び出して実行するクラス
    1. 業務ロジックを記述したGitリポジトリ
    • 2.1 Jobクラス
      • 業務ロジックの「入口」というイメージで、ここを起点に必要な業務ロジックを実行していく

それぞれのクラスの詳細については次章で説明するので、以下のようにApplicationクラスRunnerクラスJobクラスという流れで処理が行われることだけ認識すれば、かなりつまずきにくくなると思います。

3. ローカルでの実行方法がわからなかった

すでに開発されているシステムを読み解いていく上では、まずはローカルで動作させてみることが最初のゴールになるかと思います。
その際、実行したいjobのパラメータをどのように受け取って処理が進んでいくかを理解出来なかったため、つまずいてしまいました。
この点については、次章でコードを交えて説明します。

Spring Batchアプリケーション実行の全体像

ここからは、具体的なコードを見ながらSpring Batchアプリケーションの全体像を説明していきます。
前章で列挙したつまずきポイントでつまずかないように、補足しながら説明していきます!

つまずいたポイントの章で説明した通り、構造をApplicationクラスRunnerクラスJobクラスの3つに分けて説明していきます。

1. Batch処理自体の実行ロジックを記述したGitリポジトリ

1.1 Applicationクラス

ここでは単純にアプリケーションの実行を行います。実際には、Runnerクラスが呼び出される形で実行されます。

TaskApplication.java
@EnableBatchProcessing
@SpringBootApplication
public class TaskApplication {

  public static void main(String[] args) {
      SpringApplication application = new SpringApplication(TaskApplication.class);
      runtimeContext = application.run(args);
  }
}

1.2 Runnerクラス

ジョブの実行時には、業務ロジックが記述されている外部ライブラリを呼び出して実行します。

Runner.java
import com. ... .Job;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;

@Component
public class Runner implements ApplicationRunner {

    // 実行したいjarファイルを指定(ローカルにおいては.m2配下の外部ライブラリに保存)
    private final Job job;
    private final JobContext jobContext;

    @Autowired
    public Runner(JobContext jobContext, Job job) {
        this.jobContext = jobContext;
        this.job = job;
    }

    protected void dispatch(String s) {
        switch (s) {
            case "jobname_1":
                job.execute();
            ...
        }
    }

    // 実行時にプログラム引数からジョブの名前のみを取り出す処理を行う
    public void run(ApplicationArguments args){
        String job = JobsArgumentsUtils.getJob(args);
        this.dispatch(job);
    }
}

2. 業務ロジックを記述したGitリポジトリ

2.1 Jobクラス

Job.java
@Component
public class Job {

    public Job() {
    }

    public void execute() {
        // 実行したい内容を記述
    }
}

まとめ

以上が、Spring Batchアプリケーション実行の全体像になります。
つまずいたポイントでも書いたように、2つのGitリポジトリと3つのクラスそれぞれの責務の違いと処理の流れを認識しながらコードを読み解くことで、つまずきにくくなると思います。

学んだこと

Spring Batchやコンテナ技術の仕組みの概要すら分かっていない状態からおおよその全体像を掴み、無事にリリースを行なった経験から次のことを学びました。

まずは、全体像を掴まずに闇雲に調べても仕方ないということです。初めて触るアプリケーションの全体像がわからないのは仕方ないですが、その状態で闇雲に調べても時間がかかるだけです。まずはざっくりした全体像を掴み、処理の流れを意識できるようになることで効率的に開発を進めることができます。

次は、質問することの大切さです。上述した内容にも関連しますが、すでにあるシステムであれば聞いた方が早いことも多いです。少し考えて分からなければ質問してみて、そこから徐々に理解を深めていくのが効率的であると改めて認識しました。

参考文献

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/tasks-scheduled-eventbridge-scheduler.html
https://qiita.com/RyoMar/items/06e23d60d9df2d955221
https://spring.pleiades.io/spring-batch/docs/current/api/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.html
https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/ja/Ch02_SpringBatchArchitecture.html
https://spring.io/projects/spring-batch
https://aws.amazon.com/jp/what-is/batch-processing/
https://aws.amazon.com/jp/what-is/containerization/
https://qiita.com/omo_taku/items/867b0e9c7114b84edee2

脚注
  1. ただし、ユースケースによってはEKSなどの選択肢も検討する必要があります ↩︎

WealthNavi Engineering Blog

Discussion