Spring-boot: Batch apps with failed jobs should be able to return a non zero exit code

Created on 15 Aug 2018  路  12Comments  路  Source: spring-projects/spring-boot

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.

external-project

Most helpful comment

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.

All 12 comments

@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?

@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?

Hi @philwebb Can you please guide me on this, would like to wok if no one else is working on this. Thanks.

@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?

PR submitted for this issue: https://github.com/spring-projects/spring-boot/pull/15066

Also requested review from @mminella @benas

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.

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).

@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.

@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.

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.

Thanks all, let's close this one then.

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.

Was this page helpful?
0 / 5 - 0 ratings