Friday, March 29, 2013

Spring Batch - Running only one Job Instance at a time

Spring Batch - Running only one Job Instance at a time

an occasional use case in Spring Batch is the need to have only one instance of a Job running at any given time.  this might be due to restrictions on source data or some other competing aspect.  an extension of this use case is that you don't want to lose the incoming 'job start', you want to 'queue it up' for next time.

here's a simple solution composed in Spring Integration that supports the above ideal and uses the new Retry components from Spring Integration 2.2.  It's not the only way of putting a solution together for it, but it allows the separation of Job (Spring Batch) from Job Orchestration (not Spring Batch)

first - the class that's going to verify if a job is running or not (and throw and exception if it is)

package de.incompleteco.spring.batch.service;

public interface JobStatus {

  * verifies if the job name is running anywhere in the job explorer
  * @param jobName
  * @throws Exception
 public void verifyNotRunning(String jobName) throws Exception;

and the implementation

package de.incompleteco.spring.batch.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.explore.JobExplorer;

public class SimpleJobStatus implements JobStatus {

 private List jobNames;
 private JobExplorer jobExplorer;

 public SimpleJobStatus() {
  jobNames = new ArrayList();
 public void verifyNotRunning(String jobName) throws Exception {
  //check if it's a known job
  if (jobNames.contains(jobName)) {
   //check if it's running
   Set executions = jobExplorer.findRunningJobExecutions(jobName);
   if (executions != null && !executions.isEmpty()) {
    //it's running somewhere
    throw new Exception("the job " + jobName + " is curretly running");
   }//end if
  }//end if

 public void setJobNames(List jobNames) {
  this.jobNames = jobNames;

 public void setJobExplorer(JobExplorer jobExplorer) {
  this.jobExplorer = jobExplorer;


here's the Spring Integration using the retry to handle the exception and try again



so, now there are two things to note;
- the 'queue' (retry loop) is JVM bound - if the JVM dies, the 'queue' does too
- the 'verify' is based on the Job Explorer - it the Job Explorer is database, then it will go across JVM, if not, it's only for this one.

1 comment:

  1. I have this erreur : Caused by: org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'int:chain'. One of '{"":queue, ....

    Use spring integration 2.2