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 the BatchStatus 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 the JobExecution, so adding a custom ExitCodeGenerator 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.