Currently if a Spring Batch Job's ExitStatus.ExitCode
is FAILED the Boot application ends with a 0 exit code. However we have had several requests from users that would like for the application to return a non zero exit code if the ExitStatus.ExitCode
of a Spring Batch Job returns a FAILED.
This feature should be configurable where the default behavior should remain as is, but a user can configure it such that Boot app returns a non zero exit code if ExitStatus.ExitCode
is FAILED.
Comment From: toonborgers
@cppwfs I'd like to take a look at this. From some quick looking around in the code, I think the solution should be something similar to org.springframework.boot.autoconfigure.batch.JobExecutionExitCodeGenerator
, but with the configurable property as result code instead of using the ordinal of the BatchStatus
, correct?
Comment From: akoserwal
@cppwfs: 'getExitCode' is defined as abstract method in the functional interface ExitCodeGenerator
and updating getExitCode
type would change the default behaviour. We can add a new method in /batch/JobExecutionExitCodeGenerator such as String getExitCodeStatus
with option to autoconfigure return code? I can submit a PR. if this seems fine?
Comment From: nishantraut
Hi @philwebb Can you please guide me on this, would like to wok if no one else is working on this. Thanks.
Comment From: philwebb
@nishantraut I'm afraid I'm not that familiar with the internals of Spring Batch so I'm not too sure what's involved here. Probably something changes are required to JobExecutionExitCodeGenerator
but I don't know exactly how the Spring Batch ExitStatus
is obtained. Perhaps @mminella has some advice?
Comment From: dimitrisli
PR submitted for this issue: https://github.com/spring-projects/spring-boot/pull/15066
Also requested review from @mminella @benas
Comment From: fmbenhassine
Currently if a Spring Batch Job's ExitStatus.ExitCode is FAILED the Boot application ends with a 0 exit code.
This is probably because the app is executed with:
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
rather than:
public static void main(String[] args) {
System.exit(
SpringApplication.exit(
SpringApplication.run(DemoApplication.class, args)
)
);
}
as mentioned in the batch sample. If run like in the boot batch sample, a failed Spring Batch app should by default return 5 (which is the ordinal of FAILED
in the BatchStatus
enum) and not 0. Here is a quick sample:
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@EnableBatchProcessing
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
System.exit(
SpringApplication.exit(
SpringApplication.run(DemoApplication.class, args)
)
);
}
@Bean
public Job job(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
Step step = stepBuilderFactory.get("step")
.tasklet((contribution, chunkContext) -> {
throw new Exception("Boom");
}).build();
return jobBuilderFactory.get("job")
.start(step)
.build();
}
}
However we have had several requests from users that would like for the application to return a non zero exit code if the ExitStatus.ExitCode of a Spring Batch Job returns a FAILED.
I think there is no need for a new feature in boot to achieve this. Boot already emits a JobExecutionEvent
with the JobExecution
, so adding a custom ExitCodeGenerator
as a listener to this type of event is enough, something like:
@Bean
public ExitCodeGenerator exitCodeGenerator () {
return new MyExitCodeGenerator();
}
class MyExitCodeGenerator implements ExitCodeGenerator, ApplicationListener<JobExecutionEvent> {
private JobExecution jobExecution;
@Override
public int getExitCode() {
ExitStatus exitStatus = jobExecution.getExitStatus();
if (ExitStatus.FAILED.getExitCode().equals(exitStatus.getExitCode())) {
return 42;
}
return 0;
}
@Override
public void onApplicationEvent(JobExecutionEvent jobExecutionEvent) {
this.jobExecution = jobExecutionEvent.getJobExecution();
}
}
adding this bean to the previous example makes it return 42 when the job fails.
Comment From: snicoll
Thanks @benas. Looking at your sample and the original description, it is not crystal clear what should be done here. I am taking off the "ideal-for-contribution" until the scope is clarified (at least for me).
Comment From: dimitrisli
@benas sounds good. This is something the user can register so no need for a new feature in which case this issue and PR can be closed.
Comment From: fmbenhassine
@snicoll There is actually nothing to do, boot already provides a way to generate a custom exit code through the ExitCodeGenerator
. If the user wants to generate a custom exit code, he/she has to register a custom ExitCodeGenerator
as shown in the example above. So for me, the ExitCodeGenerator
API is the feature requested here.
Comment From: mminella
Sorry for the delay on chiming in on this issue. I held off because this functionality already exists in Spring Cloud Task but was broken. I merged the PR that contained the fixes yesterday. You can see what we have here https://github.com/spring-cloud/spring-cloud-task/blob/master/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java. This issue was originally opened to donate that code here.
Comment From: snicoll
Thanks all, let's close this one then.
Comment From: snicoll
This issue was originally opened to donate that code here.
Sorry @mminella I missed that part. Can you please submit a PR with that code and I am more than happy to review it.
Comment From: ghost
This
Currently if a Spring Batch Job's ExitStatus.ExitCode is FAILED the Boot application ends with a 0 exit code.
This is probably because the app is executed with:
java public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }
rather than:
java public static void main(String[] args) { System.exit( SpringApplication.exit( SpringApplication.run(DemoApplication.class, args) ) ); }
as mentioned in the batch sample. If run like in the boot batch sample, a failed Spring Batch app should by default return 5 (which is the ordinal of
FAILED
in theBatchStatus
enum) and not 0. Here is a quick sample:```java import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean;
@EnableBatchProcessing @SpringBootApplication public class DemoApplication {
public static void main(String[] args) { System.exit( SpringApplication.exit( SpringApplication.run(DemoApplication.class, args) ) ); } @Bean public Job job(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) { Step step = stepBuilderFactory.get("step") .tasklet((contribution, chunkContext) -> { throw new Exception("Boom"); }).build(); return jobBuilderFactory.get("job") .start(step) .build(); }
} ```
However we have had several requests from users that would like for the application to return a non zero exit code if the ExitStatus.ExitCode of a Spring Batch Job returns a FAILED.
I think there is no need for a new feature in boot to achieve this. Boot already emits a
JobExecutionEvent
with theJobExecution
, so adding a customExitCodeGenerator
as a listener to this type of event is enough, something like:```java @Bean public ExitCodeGenerator exitCodeGenerator () { return new MyExitCodeGenerator(); }
class MyExitCodeGenerator implements ExitCodeGenerator, ApplicationListener
{ private JobExecution jobExecution; @Override public int getExitCode() { ExitStatus exitStatus = jobExecution.getExitStatus(); if (ExitStatus.FAILED.getExitCode().equals(exitStatus.getExitCode())) { return 42; } return 0; } @Override public void onApplicationEvent(JobExecutionEvent jobExecutionEvent) { this.jobExecution = jobExecutionEvent.getJobExecution(); }
} ```
adding this bean to the previous example makes it return 42 when the job fails.
This does not work if you have configured SimplyAsyncTaskExecutor in SimpleJobLauncher.
@Override
protected JobLauncher createJobLauncher() throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository);
// To run 4 jobs parallelly.
SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
taskExecutor.setConcurrencyLimit(4);
simpleJobLauncher.setTaskExecutor(taskExecutor);
simpleJobLauncher.afterPropertiesSet();
return simpleJobLauncher;
}
Any ideas on what can I do to achieve the goal of returning non-zero status code from the batch job?
Comment From: wilkinsona
@binbeast21 We prefer to use GitHub issues only for bugs and enhancements so please ask questions such as this on Stack Overflow or Gitter.