Spring batch return custom process exit code
Solution 1
Thanks to @Mahendra I've got an idea :)
I've created a JobCompletionNotificationListener
class as @Mahendra suggested:
@Component
public class JobCompletionNotificationListener extends JobExecutionListenerSupport {
private static final Logger logger = LoggerFactory.getLogger(JobCompletionNotificationListener.class);
@Override
public void afterJob(JobExecution jobExecution) {
SingletonExitCode exitCode = SingletonExitCode.getInstance();
if(jobExecution.getStatus() == BatchStatus.COMPLETED)
{
logger.info("Exit with code " + ExitCode.NORMAL_END_OF_EXECUTION);
exitCode.setExitCode(ExitCode.NORMAL_END_OF_EXECUTION);
}
else {
logger.info("Exit with code " + ExitCode.ABNORMAL_END_OF_EXECUTION_WARNING);
exitCode.setExitCode(ExitCode.ABNORMAL_END_OF_EXECUTION_WARNING);
}
}
}
But I don't force the application to exit with System.exit()
from this class. I've implemented a simple singleton like this:
public class SingletonExitCode {
public ExitCode exitCode = ExitCode.ABNORMAL_END_OF_EXECUTION_WARNING; // Default code 3
private static SingletonExitCode instance = new SingletonExitCode();
private SingletonExitCode() {}
public static SingletonExitCode getInstance() {
return instance;
}
public void setExitCode(ExitCode exitCode) {
this.exitCode = exitCode;
}
}
and I ask the ExitCode
from my singleton after closing Spring context:
@SpringBootApplication
@EnableBatchProcessing
@Import(CoreCommonsAppComponent.class)
public class Application {
// a lot of nice things
public static void main(String... args) throws Exception{
ApplicationContext context = SpringApplication.run(Application.class, args);
logger.info("================================================");
SpringApplication.exit(context);
System.exit(SingletonExitCode.getInstance().exitCode.getCode());
}
}
I did this because if we exit directly from JobCompletionNotificationListener
class we miss an important line in the logs:
Job: [FlowJob: [name=writeErrorFromFile]] completed with the following parameters: [{-input.xml.file=c:/temp/unit-test-error.xml, -spring.batch.job.names=writeErrorFromFile, run.id=15, input.xml.file=c:/temp/unit-test-error.xml}] and the following status: [FAILED]
And seems that Spring context is not properly closed.
Solution 2
Despite of exit-status of Sprint-Batch's Job (i.e. COMPLETED or FAILED), java process will be completed successfully (and you will get process exit-code as 0).
If you want a custom exit-code for java process so that you can use it any script or somewhere else, you can use JobExecutionListener.
You can check the job's exitStatus in afterJob()
and accordingly exit the java process with your desired exit-code (i.e. 4 for FAILURE)
Example of JobExecutionListener
public class InterceptingExitStatus implements JobExecutionListener{
@Override
public void beforeJob(JobExecution jobExecution) {
}
@Override
public void afterJob(JobExecution jobExecution) {
ExitStatus exitStatus = jobExecution.getExitStatus() ;
if(exitStatus == ExitStatus.COMPLETED ){
System.exit(0);
}
if(exitStatus == ExitStatus.FAILED ){
System.exit(4);
}
}
}
and this is how you can configure job-listener in the xml file -
<job id="job">
....
....
<listeners>
<listener ref="interceptingExitStatus "/>
</listeners>
</job>
Related videos on Youtube
Grechka Vassili
Apparently, this user prefers to keep an air of mystery about them.
Updated on June 04, 2022Comments
-
Grechka Vassili almost 2 years
I have one jar with several jobs, I want to execute only one job each time and retrieve a custom exit code.
For example, I have basic job (
retrieveErrorsJob
) configuration with one step that will read an input XML file and write the data in specific database table.Application class
@SpringBootApplication @EnableBatchProcessing @Import(CoreCommonsAppComponent.class) public class Application { private static final Logger logger = LoggerFactory.getLogger(Application.class); private ConfigurationConstants constants; @Autowired public Application(ConfigurationConstants constants) { this.constants = constants; } @EventListener(ApplicationStartedEvent.class) public void idApplication() { logger.info("================================================"); logger.info(constants.APPLICATION_NAME() + "-v." + constants.APPLICATION_VERSION() + " started on " + constants.REMOTE_HOST()); logger.info("------------------------------------------------"); } public static void main(String... args) throws Exception{ ApplicationContext context = SpringApplication.run(Application.class, args); logger.info("================================================"); SpringApplication.exit(context); } }
I can choose one job from command line:
java -jar my-jar.jar --spring.batch.job.names=retrieveErrorsJob --input.xml.file=myfile.xml
Spring Batch starts the correct job.
The problem is that I need the jar to return a custom process exit integer like
ExitCode.FAILED == 4
etc. But I always have a ZERO (if ExitCode = SUCCESS or FAILED).As per the docs, I need to implement
ExitCodeMapper
interface.Code (not finished)
public class CustomExitCodeMapper implements ExitCodeMapper { private static final int NORMAL_END_EXECUTION = 1; private static final int NORMAL_END_WARNING = 2; private static final int ABNORMAL_END_WARNING = 3; private static final int ABNORMAL_END_ERROR = 4; @Override public int intValue(String exitCode) { System.out.println("EXIT CODE = " + exitCode); switch (exitCode) { case "FAILED": return ABNORMAL_END_WARNING; default: return NORMAL_END_EXECUTION; } }
}
I can't find a way to use this custom implementation. I could set the custom implementation to
CommandLineJobRunner
but how to use this class? -
lauksas almost 4 yearsThat was my first try, happens that sometimes spring does not have time to update the job status in the database because it shuts down the connection after
System.exit
so look for that -
Joy about 2 yearsWould it not kill the application immediately ? How to exit the application after the job has finished ?