Scheduling Spring Batch with Oddjob

Spring Batch is not a scheduling framework… It is intended to work in conjunction with a scheduler, not replace a scheduler’ – That’s what the Spring Batch manual says. But as luck would have it, Oddjob is a scheduler, and it can work in conjunction with Spring Batch very very easily.

A Sample Spring Batch Project

If you don’t have a Spring Batch project lying around the easiest way to get one is to follow the instructions on the Spring Batch Getting Started page. If you are having trouble with this you might be interested in The Fun I had Getting Started with Spring Batch!

Method 1 – Launch a Batch File

Very Simple. Here’s a screen shot:

Spring Batch Oddjob using the Command LineAnd here’s the configuration:

<oddjob>
  <job>
    <sequential>
      <jobs>
        <variables id="vars">
          <base>
            <file file="${user.home}/scratch/spring-batch"/>
          </base>
          <jar>
            <files files="${vars.base}/target/*.jar"/>
          </jar>
          <cp>
            <files>
              <list>
                <value value="${vars.jar}"/>
                <files files="${vars.base}/target/lib/*.jar"/>
              </list>
            </files>
          </cp>
        </variables>
        <scheduling:timer xmlns:scheduling="http://rgordon.co.uk/oddjob/scheduling">
          <schedule>
            <schedules:weekly from="MONDAY" to="FRIDAY" xmlns:schedules="http://rgordon.co.uk/oddjob/schedules">
              <refinement>
                <schedules:daily from="07:00">
                  <refinement>
                    <schedules:interval interval="00:30"/>
                  </refinement>
                </schedules:daily>
              </refinement>
            </schedules:weekly>
          </schedule>
          <job>
            <exec><![CDATA[java -cp ${vars.cp}
org.springframework.batch.core.launch.support.CommandLineJobRunner
classpath:/launch-context.xml job1]]></exec>
          </job>
        </scheduling:timer>
      </jobs>
    </sequential>
  </job>
</oddjob>

Although this looks like a big mess of XML, Oddjob’s designer user interface meant I was able to create this configuration in only a few minutes. Here’s what’s going on:

  1. The Variables job sets up the the Classpath which is all the Jar files in the target and target/lib directories.
  2. The Exec Job runs the Spring Batch CommandLineRunner using the previously defined class path.
  3. The Timer runs the Exec Job every half an hour between 07:00am and midnight, Monday to Friday.

The last 1000 lines of console output are captured by Oddjob and that’s what we can see in the right hand panel.

Method  2 – Embed in Oddjob with A Wrapper Class

Here’s a very simple wrapper class for our test project:

public class MyLauncher implements Callable<Integer> {

	public Integer call() throws Exception {

		ConfigurableApplicationContext context =
				new ClassPathXmlApplicationContext("classpath:/launch-context.xml");

		try {
			JobLauncher launcher = context.getBean(JobLauncher.class);
			Job job = (Job) context.getBean("job1");

			JobExecution jobExecution = launcher.run(job, new JobParameters());

			if (jobExecution.getExitStatus() == ExitStatus.FAILED) {
				return 1;
			}
			else {
				return 0;
			}
		}
		finally {
			context.close();
		}
	}

	@Override
	public String toString() {
		return "My Launcher";
	}
}

And here it is running:

The configuration has changed a little:

<oddjob id="this">
  <job>
    <sequential>
      <jobs>
        <variables id="vars">
          <base>
            <file file="${user.home}/scratch/spring-batch"/>
          </base>
          <classes>
            <files files="${vars.base}/target/classes"/>
          </classes>
          <cp>
            <files>
              <list>
                <value value="${vars.classes}"/>
                <files files="${vars.base}/target/lib/*.jar"/>
              </list>
            </files>
          </cp>
        </variables>
        <scheduling:timer xmlns:scheduling="http://rgordon.co.uk/oddjob/scheduling">
          <schedule>
            <schedules:weekly from="MONDAY" to="FRIDAY" xmlns:schedules="http://rgordon.co.uk/oddjob/schedules">
              <refinement>
                <schedules:daily from="07:00">
                  <refinement>
                    <schedules:interval interval="00:30"/>
                  </refinement>
                </schedules:daily>
              </refinement>
            </schedules:weekly>
          </schedule>
          <job>
            <oddjob file="${this.dir}/RunFromOddjobInner.xml" id="adhoc-oddjob">
              <classLoader>
                <url-class-loader>
                  <files>
                    <value value="${vars.cp}"/>
                  </files>
                </url-class-loader>
              </classLoader>
            </oddjob>
          </job>
        </scheduling:timer>
      </jobs>
    </sequential>
  </job>
</oddjob>

And:

<oddjob>
  <job>
    <bean class="rob.MyLauncher" id="launcher"/>
  </job>
</oddjob>

We’re using a nested Oddjob to build the class path. This is just one of many ways to let Oddjob know where classes for Job’s are, others are described in the Developer Guide. Although it’s a nested Oddjob, it still all runs in just one JVM.

Oddjob keeps the last 1000 lines of log output from a component for display purposes, again you can see this in right hand panel. The format is different to the console output in method 1, because it’s Oddjob that’s dictating the pattern, not Spring Batch.

And that’s how to schedule a Spring Batch application from Oddjob. All the source code is available from the Oddjob Oddments Directory on Sourceforge.

Comments are closed.