Help us understand the problem. What is going on with this article?

SpringでExitCodeを返す

よくわからないで始めるとこうなる

Java(Spring)を触って3ヶ月、いろんなことを片手間にやってきたので、ちゃんと理解せず実装している今日この頃です。

SpringBatchでバッチを組んでください、と言われてガリガリとバッチを作りました。
Rundeck上で定期実行させて、エラーがあればSlack通知投げるという、ごく単純なバッチです(SpringBatchでジョブのDB管理しないとか、ちょこちょこ細かい前提はありました)。

で、実装に気を取られガツガツ作っていざジョブスケジューラに載せてみると、上司がサンプルにくれたテンプレートはExitCodeが必ず0で返ってきます。
というのも、もらったテンプレートもそうでしたが、各所にあがっている下記のような記述は、当然っちゃ当然ですが、runしているだけなので、ExitCodeなんてなにもハンドリングしてくれていないみたいです(SpringApplicationが起動するまでに生じたエラー(DB接続できなかったとか)は拾えますが)。

Application.java
@SpringBootApplication
@RestController
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

単純に、エラーだったらExitCodeを0以外で返せればいい。
初めはCommandLineJobRunnerを使おうとしてうまく起動せず(Commandから呼び出すとDataSourceが云々のエラーで進まず。たぶん、jobPathの設定方法を間違えたのだと思います)。
次に苦し紛れにSpringBatchのJobListenerでJobのステータスをみながらSystem.exitを返していたのですが、Job実行時の想定外のエラーなど、Listenerまでたどり着かない処理は当然ExitCode=0になるのです。
ググりまくって出てきた通りにやってみたら、一応のハンドリングはできました。

Application.java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        var context = SpringApplication.run(Application.class, args);
        System.exit(SpringApplication.exit(context, () -> 0));
    }
}

上記が思った挙動かどうか確かめるため、下記2点をなんとなーく中身をみて、なんとなーく確認しました。
(詳細は、時間があるときに読めたら。。。)

ConfigurableApplicationContext

SpringApplication.runで作成される、アプリケーションの振る舞いが記述されたオブジェクトのようです。
startup/shutdownを外から操作できるようにしてあるインターフェースで、パラメータの設定などのメソッドがありました。
なので、おそらくアプリケーションを終了するときの挙動と結果もここに記載されているのだと思います。

なお、run実行中にエラーになったらIlligalExceptionを返すところが、Spring起動時にエラーならExitCode=0にならない理由だと思われます。

SpringApplication.exit

ヘッダのコメント

  • Static helper that can be used to exit a {@link SpringApplication} and obtain a
  • code indicating success (0) or otherwise. Does not throw exceptions but should

翻訳

{@link SpringApplication}を終了し、成功(0)などを示すコードを取得するために使用できる静的ヘルパー。

SpringApplicationのExitCodeを管理するための処理のようです。
ExitCodeGeneratorsではExitCodeのカスタムができます。
- https://www.codeflow.site/ja/article/spring-boot-exit-codes

で、中ではこのExitCodeGeneratorsをつかってExitCodeを作成しています。
何もカスタムしない状態で実行時エラーにすると、generators(SpringApplication.java:Line1290)でgenerator.addAll(beans)したときに登録されるJobExecutionExitCodeGeneratorが実行時エラーをキャッチしてExitCodeを返していました。
SpringApplication.java:Line1301でexitCode != 0の場合には、contextからExitCodeEventを発行してくれて、これが実行したシステム側に返ってくるようです。

JobExecutionExitCodeGeneratorは、JobExecution単位でもっているので、Job単位にExitCodeをキャッチしてくれているようです。
ちゃんとStepでFailになっていればエラーを履いてくれるはず!

最後に

ものすごく大雑把な理解ですが、JobExecutionごとのエラーをキャッチしてExitCodeを出力しているようです。
afterStepで、Success以外はFailにする処理をいれているため、Stepが失敗して入れば、Jobもエラーとして判断できるようになりました。
いったん、動けばいいからこんなもので!

ご指摘があればコメントいただけるとありがたいです!!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした