Archive for April, 2012

24
Apr
12

Shutting Down Spring Batch Jobs Gracefully

This page describes how to exit batch jobs gracefully when the system sends the SIGINT to the JVM. If we ignore these signals the jobs will be left hanging. The solution is to request the Spring Job-operator to gracefully stop the job and in the process save any intermediate data to the spring batch status tables.

Requirements

  • Fully working Spring Batch application
  • Configured Spring batch Job Repository

Start by adding the following to the spring configuration file:

<beans:bean id="jobRegistry" 
	class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<beans:bean id="jobRegistryBeanPostProcessor"
	class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
    <beans:property name="jobRegistry" ref="jobRegistry"/>
</beans:bean>	
<beans:bean id="jobOperator" 
	class="org.springframework.batch.core.launch.support.SimpleJobOperator">
		<beans:property name="jobExplorer" ref="jobExplorer"/>
		<beans:property name="jobRepository" ref="jobRepository" />
		<beans:property name="jobRegistry" ref="jobRegistry" />
		<beans:property name="jobLauncher" ref="jobLauncher" />
</beans:bean>
<beans:bean id="jobExplorer" 
	class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
	<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<beans:bean name="processShutdownListener" 
	class="com.test.batch.listeners.ProcessShutdownListener">
	<beans:property name="jobOperator" ref="jobOperator"/>
</beans:bean>

Inside the job.xml

	<listeners>
		<listener ref="processShutdownListener"/>
	</listeners>

And finally the listener

package com.test.batch.listeners;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.launch.JobExecutionNotRunningException;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;

/**
 * This class listens to events from the Operating System requesting the Batch
 * to shutdown. For example when the user hits CTRL-C or the system is shutting
 * down. If we ignore these signals the jobs will be left hanging. This class
 * attempts to remedy this situation by requesting the JobOperator to gracefully
 * stop a job when the JVM calls the shutdown hook.
 */
public class ProcessShutdownListener implements JobExecutionListener {
	private static final Log logger = 
		LogFactory.getLog(ProcessShutdownListener.class);
	
	private JobOperator jobOperator;
	
	@Override
	public void afterJob(JobExecution jobExecution) { /* do nothing. */ }

	@Override
	public void beforeJob(final JobExecution jobExecution) {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				super.run();
				try {
					jobOperator.stop(jobExecution.getId());
					while(jobExecution.isRunning()) {
						logger.info("waiting for job to stop...");
						try {Thread.sleep(100);} catch (InterruptedException e) {}
					}
				} catch (NoSuchJobExecutionException e) { // ignore
				} catch (JobExecutionNotRunningException e) { // ignore
				}
			}
		});
	}

	public void setJobOperator(JobOperator jobOperator) {
		this.jobOperator = jobOperator;
	}

}



Follow

Get every new post delivered to your Inbox.

Join 49 other followers