Announcement Announcement Module
Collapse
No announcement yet.
Jobs within a Job Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Jobs within a Job

    Hi,
    I would like to programmatically start some jobs from within a Job that has been launched asynchronously.

    When I do so, I get the following:
    Code:
    java.lang.IllegalStateException: Existing transaction detected in JobRepository.Please fix this and try again (e.g. remove @Transactional annotations from client).
    This is obviously happening because the parent job is not complete, so the transaction is still "active". How can I force the child jobs to join that transaction instead of complaining.

    I have written a Tasklet from where I am launching these jobs. I tried setting the @Transaction attribute on the execute(...) method to SUPPORTS explicitly, but that did not help.

    Can someone please suggest how I can achieve the starting of several jobs from within a job and not run into this transaction issue.

    The full stack is:
    Code:
    2011-07-21 14:16:31,714 [SimpleAsyncTaskExecutor-18] ERROR org.springframework.batch.core.step.AbstractStep  #### Encountered an error executing the stepjava.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove @Transactional annotations from clie
    nt).
            at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:164)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
            at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
            at $Proxy2.createJobExecution(Unknown Source)
            at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:111)at com.xxx.adc.batch.SplitFilesTasklet.execute(SplitFilesTasklet.java:92)
            at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:386)
            at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
            at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
            at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
            at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
            at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
            at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
            at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
            at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
            at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
            at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
            at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
            at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
            at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
            at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
            at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
            at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run
    (SimpleJobLauncher.java:120)
    Thanks!

  • #2
    <bean id="jobRepository"
    class="org.springframework.batch.core.repository.s upport.MapJobRepositoryFactoryBean">
    <property name="validateTransactionState" value="false"/>
    </bean>

    This should do the trick... I an not sure if it's safe to do that. More on that:

    https://jira.springsource.org/browse/BATCH-1668

    Comment


    • #3
      Any other method of doing this ?

      i have a reader , which read data-base, gets data, now for each record, i need to query the different database to get a lot of data and write to DB.
      i can use the Item processor, but the data is huge, i cannot hold the data in memory and pass it to writer.

      How do i process this ?

      Comment


      • #4
        If you really want to launch a Job from within a Job why not use a JobStep (it has XML namespace support as well)?

        Comment


        • #5
          Hi Dave,
          Nice idea,
          For every record in the reader, i need to call a job, and pass that row value as parameter ?

          can you just post me a simple example ?

          Comment


          • #6
            JobStep example

            This seems to work:

            Code:
            	<job id="topJob" xmlns="http://www.springframework.org/schema/batch"  >
            		<step id="topJob.step1" next="topJob.step2">
            			<job ref="decryptJobStep"  job-parameters-extractor="jobParametersExtractor"/>
            		</step>
            		<step id="topJob.step2" next="topJob.split3">
            		    <job ref="processXXXJobStep" job-parameters-extractor="jobParametersExtractor"/>
            		</step>
            						    
            		<split id="topJob.split3" task-executor="myTaskExecutor" >
            		    <flow>
            		        <step id="topJob.step3" >
            		        	<job ref="processYYY1JobStep" job-parameters-extractor="jobParametersExtractor"/>
            		        </step>
            		    </flow>
            		    <flow>
            		        <step id="topJob.step4" >
            		        	<job ref="processYYY2JobStep" job-parameters-extractor="jobParametersExtractor"/>
            		        </step>
            		    </flow>
            		    <flow>
            		        <step id="topJob.step5" >
            		        	<job ref="processYYY3JobStep" job-parameters-extractor="jobParametersExtractor"/>
            		        </step>
            		    </flow>
            		    <flow>
            		        <step id="topJob.step6" >
            		        	<job ref="processYYY4JobStep" job-parameters-extractor="jobParametersExtractor"/>
            		        </step>
            		    </flow>
            		</split>
            	</job>
            	
            
            
            	<job id="decryptJobStep" xmlns="http://www.springframework.org/schema/batch"  >
            		<step id="decryptJobStep.step1">
            		    <tasklet ref="decryptTasklet" />
            		</step>
            	</job>
            	<bean id="decryptTasklet" class = "com.acme...DecryptFileTasklet" >
            	   <property name="jobRepository" ref="jobRepository" />
            	   <property name="jobLauncher" ref="jobLauncher" />	
            	</bean>
            	
            	<job id="processYYY1JobStep" xmlns="http://www.springframework.org/schema/batch"  >
            		<step id="processYYY1JobStep.step1">
            		    <tasklet ref="processYYY1Tasklet" />
            		</step>
            	</job>
            	<bean id="processYYY1Tasklet" class = "com.acme...ProcessYYY1Tasklet" >
            	   <property name="jobRepository" ref="jobRepository" />
            	   <property name="jobLauncher" ref="jobLauncher" />	
            	</bean>
            HTH

            Comment


            • #7
              Hi spongybob,

              For every record in the reader, i need to call a job, and pass that row value as parameter ?
              can you just post me a simple example ?

              Your example, looks like, sequential job execution

              Comment


              • #8
                Simple Job within a Job

                Hi,
                I don't have an example but isn't this what you want:

                Code:
                <job id="topJob" xmlns="http://www.springframework.org/schema/batch"  >
                		<step id="topJob.step1">
                			<job ref="aJobStep" />
                		</step>
                
                </job>
                
                <job id="aJobStep" xmlns="http://www.springframework.org/schema/batch"  >
                	<step id="aJobStep.step1">
                	    <tasklet>
                	    	 <chunk reader="itemReader" writer="itemWriter" processor="itemProcessor"/>
                	    </tasklet>
                	</step>
                </job>

                Comment


                • #9
                  This topJob will run only once.

                  But what i wanted to do is;
                  Job-A read DB and fetch N rows, for each ROW run JOB-b

                  Comment


                  • #10
                    I think I would recommend an alternative approach where you use a Partitioner instead of an ItemReader to split up the work. If you really want to do it with an ItemReader you need to launch your sub-jobs without a transaction (as you already found) - there is probably more than one way to do that, but the easiest would be to switch off the transaction in the TaskletStep using a custom propagation.

                    Comment

                    Working...
                    X