Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing in JobExecutionContext from tasklet and accessing in another tasklet

Tags:

I have a requirement in which a tasklet, stores all the files in the directories in an arraylist. The size of the list is stored in the job execution context. Later this count is accessed from another tasklet in another step. How do it do this. I tried to store in jobexecution context, at runtime throws unmodifiable collection exception,

public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) throws Exception {     StepContext stepContext = arg1.getStepContext();     StepExecution stepExecution = stepContext.getStepExecution();     JobExecution jobExecution = stepExecution.getJobExecution();     ExecutionContext jobContext = jobExecution.getExecutionContext();      jobContext.put("FILE_COUNT",150000); 

also stored the stepexection reference in beforestep annotation .still not possioble.kindly let me know ,how to share data between two tasklets.

like image 471
Dead Programmer Avatar asked Nov 14 '11 03:11

Dead Programmer


People also ask

How do I pass information from one step to another in Spring Batch?

It is often useful to pass information from one step to another. This can be done through the ExecutionContext . The catch is that there are two ExecutionContexts : one at the Step level and one at the Job level.

How do I share data between Tasklets?

Data passing between steps using tasklet model In order to save and fetch passing data, get ExecutionContext from ChunkContext and pass the data between the steps. Sr. No. Set the value to be passed to the after step in the ExecutionContext of the step execution context.

How do I get jobExecutionContext in writer?

Make your item writer with step scope, then make use of expression like #{jobParameters['theKeyYouWant']} or #{jobExecutionContext['someOtherKey']} for value injecting to you item writer. 1. you need the bean being step scope, 2. you need setter for "context" property.

What is execution context in Spring Batch?

An ExecutionContext is a set of key-value pairs containing information that is scoped to either StepExecution or JobExecution . Spring Batch persists the ExecutionContext , which helps in cases where you want to restart a batch run (e.g., when a fatal error has occurred, etc.).


2 Answers

you have at least 4 possibilities:

  1. use the ExecutionPromotionListener to pass data to future steps
  2. use a (spring) bean to hold inter-step data, e.g. a ConcurrentHashMap
    • without further action this data won't be accessible for a re-start
  3. access the JobExecutionContext in your tasklet, should be used with caution, will cause thread problems for parallel steps
  4. use the new jobscope (introduced with spring batch 3)

Code Example for accessing JobExecution from Tasklet:

  1. setting a value

    public class ChangingJobExecutionContextTasklet implements Tasklet {      /** {@inheritDoc} */     @Override     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {         // set variable in JobExecutionContext         chunkContext                 .getStepContext()                 .getStepExecution()                 .getJobExecution()                 .getExecutionContext()                 .put("value", "foo");          // exit the step         return RepeatStatus.FINISHED;     }  } 
  2. extracting a value

    public class ReadingJobExecutionContextTasklet implements Tasklet {      private static final Logger LOG = LoggerFactory.getLogger(ChangingJobExecutionContextTasklet.class);      /** {@inheritDoc} */     @Override     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {         // pull variable from JobExecutionContext         String value = (String) chunkContext                                     .getStepContext()                                     .getStepExecution()                                     .getJobExecution()                                     .getExecutionContext()                                     .get("value");          LOG.debug("Found value in JobExecutionContext:" + value);          // exit the step         return RepeatStatus.FINISHED;     } } 

i created code examples for the first 3 solutions in my spring-batch-examples github repository, see module complex and package interstepcommunication

like image 89
Michael Pralow Avatar answered Sep 20 '22 18:09

Michael Pralow


Another way is to use StepExecutionListener which is called after step execution. Your tasklet can implements it and share local attribute.

public class ReadingJobExecutionContextTasklet implements Tasklet, StepExecutionListener {     private String value;      @Override     public ExitStatus afterStep(StepExecution stepExecution) {         ExecutionContext jobExecutionContext = stepExecution.getJobExecution().getExecutionContext();          jobExecutionContext.put("key", value);         //Return null to leave the old value unchanged.         return null;     } } 

So, in the step, your bean is a tasklet and a listener like bellow. You should also configure the scope of you step to "step" :

    <batch:step id="myStep" next="importFileStep">         <batch:tasklet>             <ref bean="myTasklet"/>             <batch:listeners>                 <batch:listener ref="myTasklet"/>             </batch:listeners>         </batch:tasklet>     </batch:step>      <bean id="myTasklet" class="ReadingJobExecutionContextTasklet" scope="step"> 
like image 36
user1067920 Avatar answered Sep 19 '22 18:09

user1067920