diff --git a/src/site/docbook/reference/job.xml b/src/site/docbook/reference/job.xml index dcff2a498..dd4c891e0 100644 --- a/src/site/docbook/reference/job.xml +++ b/src/site/docbook/reference/job.xml @@ -4,9 +4,9 @@ Configuring and Running a Job - In the domain section , the - overall architecture design was discussed, using the following - diagram as a guide: + In the domain section , the overall + architecture design was discussed, using the following diagram as a + guide: @@ -38,11 +38,11 @@ required dependencies: a name, JobRepository , and a list of Steps. - <job id="footballJob"> - <step id="playerload" parent="s1" next="gameLoad"/> - <step id="gameLoad" parent="s2" next="playerSummarization"/> - <step id="playerSummarization" parent="s3"/> -</job> + + + + +]]> The examples here use a parent bean definition to create the steps; see the section on step configuration @@ -50,11 +50,11 @@ defaults to referencing a repository with an id of 'jobRepository', which is a sensible default. However, this can be overridden explicitly: - <job id="footballJob" job-repository="specialRepository"> - <step id="playerload" parent="s1" next="gameLoad"/> - <step id="gameLoad" parent="s3" next="playerSummarization"/> - <step id="playerSummarization" parent="s3"/> -</job> + job-repository="specialRepository" + + + +]]> In addition to steps a job configuration can contain other elements that help with parallelisation (<split/>), @@ -78,16 +78,16 @@ be run as part of a new JobInstance, then the restartable property may be set to 'false': - <job id="footballJob" restartable="false"> + restartable="false" ... -</job> +]]> To phrase it another way, setting restartable to false means "this Job does not support being started again". Restarting a Job that is not restartable will cause a JobRestartException to be thrown: - Job job = new SimpleJob(); + +}]]> This snippet of JUnit code shows how attempting to create a JobExecution the first time for a non restartable @@ -118,40 +118,40 @@ catch (JobRestartException e) { SimpleJob allows for this by calling a JobListener at the appropriate time: - public interface JobExecutionListener { + +}]]> JobListeners can be added to a SimpleJob via the listeners element on the job: - <job id="footballJob"> - <step id="playerload" parent="s1" next="gameLoad"/> - <step id="gameLoad" parent="s2" next="playerSummarization"/> - <step id="playerSummarization" parent="s3"/> - <listeners> + + + + +]]> <listeners> <listener ref="sampleListener"/> </listeners> -</job> +]]> It should be noted that afterJob will be called regardless of the success or failure of the Job. If success or failure needs to be determined it can be obtained from the JobExecution: - public void afterJob(JobExecution jobExecution){ + +}]]> The annotations corresponding to this interface are: @@ -184,19 +184,19 @@ catch (JobRestartException e) { Job with two listeners and one Step, "step1". - <job id="baseJob" abstract="true"> - <listeners> - <listener ref="listenerOne"/> - <listeners> -</job> + + + + + -<job id="job1" parent="baseJob3"> - <step id="step1" parent="standaloneStep"/> + + - <listeners merge="true"> - <listener ref="listenerTwo"/> - <listeners> -</job> + + + +]]> Please see the section on Inheriting from a Parent Step @@ -216,10 +216,10 @@ catch (JobRestartException e) { of a validator is supported through the XML namespace through a child element of the job, e.g>: - <job id="job1" parent="baseJob3"> - <step id="step1" parent="standaloneStep"/> - <validator ref="paremetersValidator"/> -</job> + + + +]]> The validator can be specified as a reference (as above) or as a nested bean definition in the beans namespace. @@ -227,12 +227,17 @@ catch (JobRestartException e) {
+ + Configuring a JobRepository - As described in earlier, the JobRepository is - used for basic CRUD operations of the various persisted domain objects - within Spring Batch, such as JobExecution and + + + As described in earlier, the + JobRepository + is used for basic CRUD operations of the various persisted + domain objects within Spring Batch, such as + JobExecution and StepExecution. It is required by many of the major framework features, such as the JobLauncher, Job, and Step. The batch @@ -241,22 +246,26 @@ catch (JobRestartException e) { collaborators. However, there are still a few configuration options available: - <job-repository id="jobRepository" + + + +/>]]> + + None of the configuration options listed above are required except the id. If they are not set, the defaults shown above will be used. They - are shown above for awareness purposes. The max-varchar-length defaults to 2500, which is the length of the long - VARCHAR - columns in the sample schema scripts used - to store things like exit code descriptions. If you don't modify the schema - and you don't use multi-bye characters you shouldn't need to change it. + are shown above for awareness purposes. The + max-varchar-length defaults to 2500, which is the + length of the long VARCHAR columns in the sample schema scripts + + used to store things like exit code descriptions. If you don't modify the schema and you don't use multi-bye characters you shouldn't need to change it.
Transaction Configuration for the JobRepository @@ -277,24 +286,28 @@ catch (JobRestartException e) { that the SERIALIZED will cause problems, as long as the database platform supports it. However, this can be overridden: - <job-repository id="jobRepository" - isolation-level-for-create="REPEATABLE_READ" /> + + isolation-level-for-create="REPEATABLE_READ"]]> + If the namespace or factory beans aren't used then it is also essential to configure the transactional behavior of the repository using AOP: - <aop:config> - <aop:advisor - pointcut="execution(* org.springframework.batch.core..*Repository+.*(..))"/> - <advice-ref="txAdvice" /> -</aop:config> + + + + + -<tx:advice id="txAdvice" transaction-manager="transactionManager"> - <tx:attributes> - <tx:method name="*" /> - </tx:attributes> -</tx:advice> + + + + +]]> + This fragment can be used as is, with almost no changes. Remember also to include the appropriate namespace declarations and to make sure @@ -302,6 +315,8 @@ catch (JobRestartException e) { classpath.
+ +
Changing the Table Prefix @@ -314,8 +329,8 @@ catch (JobRestartException e) { meta data tables is needed within the same schema, then the table prefix will need to be changed: - <job-repository id="jobRepository" - table-prefix="SYSTEM.TEST_" /> + table-prefix="SYSTEM.TEST_"]]> Given the above changes, every query to the meta data tables will be prefixed with "SYSTEM.TEST_". BATCH_JOB_EXECUTION will be referred to @@ -327,6 +342,8 @@ catch (JobRestartException e) {
+ +
In-Memory Repository @@ -337,10 +354,10 @@ catch (JobRestartException e) { this reason, Spring batch provides an in-memory Map version of the job repository: - <bean id="jobRepository" - class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"> - <property name="transactionManager" ref="transactionManager"/> -</bean> + + +]]> Note that the in-memory repository is volatile and so does not allow restart between JVM instances. It also cannot guarantee that two @@ -356,6 +373,8 @@ catch (JobRestartException e) { ResourcelessTransactionManager useful.
+ +
Non-standard Database Types in a Repository @@ -366,10 +385,10 @@ catch (JobRestartException e) { shortcut and use it to set the database type to the closest match: - <bean id="jobRepository" class="org...JobRepositoryFactoryBean"> - <property name="databaseType" value="db2"/> - <property name="dataSource" ref="dataSource"/> -</bean> + + + +]]> (The JobRepositoryFactoryBean tries to auto-detect the database type from the DataSource @@ -384,6 +403,8 @@ catch (JobRestartException e) { interfaces that the SimpleJobRepository depends on and wire one up manually in the normal Spring way.
+ +
@@ -395,10 +416,10 @@ catch (JobRestartException e) { a JobRepository, in order to obtain an execution: - <bean id="jobLauncher" - class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> - <property name="jobRepository" ref="jobRepository" /> -</bean> + + +]]> Once a JobExecution is @@ -442,13 +463,13 @@ catch (JobRestartException e) { configured to allow for this scenario by configuring a TaskExecutor: - <bean id="jobLauncher" - class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> - <property name="jobRepository" ref="jobRepository" /> - <property name="taskExecutor"> - <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" /> - </property> -</bean> + + + + + +]]> Any implementation of the spring TaskExecutor interface can be used to control how jobs are asynchronously @@ -545,27 +566,26 @@ catch (JobRestartException e) { name second. All arguments after these are considered to be JobParameters and must be in the format of 'name=value': - bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date(date)=2007/05/05 + bash$ - In most cases you would want to use a manifest to - declare your main class in a jar, but for simplicity, the - class was used directly. This example is using the same - 'EndOfDay' example from the domain - section. The first argument is 'endOfDayJob.xml', which - is the Spring ApplicationContext - containing the + In most cases you would want to use a manifest to declare your + main class in a jar, but for simplicity, the class was used directly. + This example is using the same 'EndOfDay' example from the domain section. The first argument is + 'endOfDayJob.xml', which is the Spring + ApplicationContext containing the Job. The second argument, 'endOfDay' represents the job name. The final argument, 'schedule.date(date)=2007/05/05' will be converted into JobParameters. An example of the XML configuration is below: - <job id="endOfDay"> - <step id="step1" parent="simpleStep" /> -</job> + + + -<!-- Launcher details removed for clarity --> -<beans:bean id="jobLauncher" - class="org.springframework.batch.core.launch.support.SimpleJobLauncher" /> + +]]> This example is overly simplistic, since there are many more requirements to a run a batch job in Spring Batch in general, but it @@ -603,11 +623,11 @@ catch (JobRestartException e) { to a number using the ExitCodeMapper interface: - public interface ExitCodeMapper { + +}]]> The essential contract of an ExitCodeMapper is that, given a string exit @@ -666,7 +686,7 @@ catch (JobRestartException e) { is required when handling an HttpRequest. An example is below: - @Controller + +}]]>
@@ -736,9 +756,9 @@ public class JobLauncherController { query the repository for existing executions. This functionality is provided by the JobExplorer interface: - public interface JobExplorer { + getJobInstances(String jobName, int start, int count); JobExecution getJobExecution(Long executionId); @@ -746,10 +766,10 @@ public class JobLauncherController { JobInstance getJobInstance(Long instanceId); - List<JobExecution> getJobExecutions(JobInstance jobInstance); + List getJobExecutions(JobInstance jobInstance); - Set<JobExecution> findRunningJobExecutions(String jobName); -} + Set findRunningJobExecutions(String jobName); +}]]> As is evident from the method signatures above, JobExplorer is a read-only version of the @@ -757,8 +777,8 @@ public class JobLauncherController { JobRepository, it can be easily configured via a factory bean: - <bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean" - p:dataSource-ref="dataSource" /> + ]]> Earlier in this chapter, it was mentioned that the table prefix of the @@ -767,8 +787,8 @@ public class JobLauncherController { JobExplorer is working with the same tables, it too needs the ability to set a prefix: - <bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean" - p:dataSource-ref="dataSource" p:tablePrefix="BATCH_" /> + p:tablePrefix="BATCH_" ]]>
@@ -784,7 +804,7 @@ public class JobLauncherController { the framework and this is based on a simple map from job name to job instance. It is configured simply like this: - <bean id="jobRegistry" class="org.spr...MapJobRegistry" /> + ]]> There are two ways to populate a JobRegistry automatically: using a bean post processor and using a registrar lifecycle component. These @@ -796,9 +816,9 @@ public class JobLauncherController { This is a bean post-processor that can register all jobs as they are created: - <bean id="jobRegistryBeanPostProcessor" class="org.spr...JobRegistryBeanPostProcessor"> - <property name="jobRegistry" ref="jobRegistry"/> -</bean> + + +]]> Athough it is not strictly necessary the post-processor in the example has been given an id so that it can be included in child @@ -823,18 +843,18 @@ public class JobLauncherController { integrate jobs contributed from separate modules of an application. - <bean class="org.spr...AutomaticJobRegistrar"> - <property name="applicationContextFactories"> - <bean class="org.spr...ClasspathXmlApplicationContextsFactoryBean"> - <property name="resources" value="classpath*:/config/job*.xml" /> - </bean> - </property> - <property name="jobLoader"> - <bean class="org.spr...DefaultJobLoader"> - <property name="jobRegistry" ref="jobRegistry" /> - </bean> - </property> -</bean> + + + + + + + + + + + +]]> The registrar has two mandatory properties, one is an array of ApplicationContextFactory (here created from a @@ -875,14 +895,14 @@ public class JobLauncherController { provides for these types of operations via the JobOperator interface: - public interface JobOperator { + getExecutions(long instanceId) throws NoSuchJobInstanceException; - List<Long> getJobInstances(String jobName, int start, int count) + List getJobInstances(String jobName, int start, int count) throws NoSuchJobException; - Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException; + Set getRunningExecutions(String jobName) throws NoSuchJobException; String getParameters(long executionId) throws NoSuchJobExecutionException; @@ -902,12 +922,12 @@ public class JobLauncherController { String getSummary(long executionId) throws NoSuchJobExecutionException; - Map<Long, String> getStepExecutionSummaries(long executionId) + Map getStepExecutionSummaries(long executionId) throws NoSuchJobExecutionException; - Set<String> getJobNames(); + Set getJobNames(); -} +}]]> The above operations represent methods from many different interfaces, such as JobLauncher, @@ -917,20 +937,20 @@ public class JobLauncherController { implementation of JobOperator, SimpleJobOperator, has many dependencies: - <bean id="jobOperator" class="org.spr...SimpleJobOperator"> - <property name="jobExplorer"> - <bean class="org.spr...JobExplorerFactoryBean"> - <property name="dataSource" ref="dataSource" /> - </bean> - </property> - <property name="jobRepository" ref="jobRepository" /> - <property name="jobRegistry" ref="jobRegistry" /> - <property name="jobLauncher" ref="jobLauncher" /> -</bean> - - If you set the table prefix on the job repository, don't - forget to set it on the job explorer as well. + + + + + + + + + +]]> + + If you set the table prefix on the job repository, don't forget to set it on the job explorer as well. +
@@ -955,11 +975,11 @@ public class JobLauncherController { Job to force the Job to a new instance: - public interface JobParametersIncrementer { + +}]]> The contract of JobParametersIncrementer is that, given a Job, as shown below: - public class SampleIncrementer implements JobParametersIncrementer { + +}]]> In this example, the value with a key of 'run.id' is used to discriminate between JobInstances. If the @@ -995,9 +1015,9 @@ public class JobLauncherController { be associated with Job via the 'incrementer' attribute in the namespace: - <job id="footballJob" incrementer="sampleIncrementer"> + incrementer="sampleIncrementer" ... -</job> +]]>
@@ -1007,8 +1027,8 @@ public class JobLauncherController { JobOperator is gracefully stopping a Job: - Set<Long> executions = jobOperator.getRunningExecutions("sampleJob"); -jobOperator.stop(executions.iterator().next()); + executions = jobOperator.getRunningExecutions("sampleJob"); +jobOperator.stop(executions.iterator().next()); ]]> The shutdown is not immediate, since there is no way to force immediate shutdown, especially if the execution is currently in @@ -1019,5 +1039,30 @@ jobOperator.stop(executions.iterator().next()); BatchStatus.STOPPED, save it, then do the same for the JobExecution before finishing.
+ +
+ Aborting a Job + + A job execution which is FAILED can be + restartsed (if the Job is restartable). A job execution whose status is + ABORTED will not be restarted by the framework. + The ABORTED status is also used in step + executions to mark them as skippable in a restarted job execution: if a + job is executing and encounters a step that has been marked + ABORTED in the previous failed job execution, it + will move on to the next step (as determined by the job flow definition + and the step execution exit status). + + If the process died ("kill -9" or server + failure) the job is, of course, not running, but the JobRepository has + no way of knowing because no-one told it before the process died. You + have to tell it manually that you know that the execution either failed + or should be considered aborted (change its status to + FAILED or ABORTED) - it's + a business decision and there is no way to automate it. Only change the + status to FAILED if it is not restartable, or if + you know the restart data is valid. There is a utility in Spring Batch + Admin JobService to abort a job execution. +