CarrieVS
CarrieVS

Reputation: 140

Make a spring-batch job exit with non-zero code if an exception is thrown

I'm trying to fix a spring-batch job which is launched from a shell script. The script then checks the process exit code to determine whether the job has succeeded. Java, however, exits 0 even if the program ended with an exception, unless System.exit was specifically called with a different code, so the script always reports success.

Is there a way to make spring-batch return a non-zero code on failure? To be clear, I'm not talking about the ExitStatus or BatchStatus, but the actual exit code of the java process.

If there's no way to tell spring-batch to return non-zero, can I safely use System.exit in a Tasklet (or a Listener) without interfering with anything that spring-batch does under the hood after an exception?

Failing that, can anyone suggest a way to get the BatchStatus or some other indicator of failure back to the shell script?

Upvotes: 3

Views: 9816

Answers (3)

Jon Freedman
Jon Freedman

Reputation: 9697

As per this github issue it's recommended to pass the result of SpringApplication#exit to System#exit. You don't need to access an ExitCodeGenerator instance directly or manually close the context.

ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
int exitCode = SpringApplication.exit(context);
System.exit(exitCode);

Upvotes: 4

CarrieVS
CarrieVS

Reputation: 140

I solved this some time ago - apologies that I did not update sooner.

Spring Batch does exit non-zero on an failed job, but there's a subtle catch.

If a job step has no transitions explicitly defined it will by default end the job on success and fail the job on failure (of the step).

If, however, the step has a transition defined for any result (e.g. to the next step on success), there is no default transition for any other result, and if it fails the job won't be properly failed. So you have to explicitly define a "fail on FAILED" transition (typically, for all steps except the last).

Upvotes: 1

Hansjoerg Wingeier
Hansjoerg Wingeier

Reputation: 4444

I would not recommend calling System.exit() from a tasklet, since the job will NOT finish completely and hence some entries in BATCH_-Tables could be left in an inconsistent state.

If you use the class CommandLineJobRunner to start your batch, then the return code according to the BatchStatus is returned (CommandLineJobRunner can be configured with an SystemExiter; as default it uses a JvmSystemExiter which calls System.exit() at the very end). However, this solution circumvents SpringBoot.

Therefore, if you want to use springboot, I'd recommend writing your own Launch-Wrapper main -method. Something like

public static void main(String[] args) throws Exception {
  // spring boot application startup
  SpringApplication springApp = new SpringApplication(.. your context ..);

  // calling the run method returns the context
  // pass your program arguments
  ConfigurableApplicationContext context = springApp.run(args);

  // spring boot uses exitCode Generators to calculate the exit status
  // there should be one implementation of the ExitCodeGenerator interface
  // in your context. Per default SpringBoot uses the JobExecutionExitCodeGenerator
  ExitCodeGenerator exitCodeGen = context.getBean(ExitCodeGenerator.class);

  int code = exitCodeGen.getExitCode();
  context.close();
  System.exit(code);
}

Upvotes: 2

Related Questions