Reputation: 140
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
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
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
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