Gustavo Fuhr
Gustavo Fuhr

Reputation: 37

Spring Batch: execute same job with different parameters

I'm newbie in sprint batch, and I couldn't find an answer for my problem.

I'm trying to implement a JOB using spring boot and spring batch. My JOB needs a parameter, so I'm executing the application like this:

java -jar -Dspring.profiles.active=gus /applications/botbit-batch/botbit-batch-1.0.0.jar --spring.batch.job.names=persistCustomerSuccessMetrics date=2015-12-13

In bold, is the parameter I need.

I executed the application a first time, but in later executions my job allways use the parameter I passed in the first execution.

The logs shows:

Running default command line with: 
[spring.batch.job.names=persistCustomerSuccessMetrics, date=2015-12-13]

and a few lines after:

Job: [FlowJob: [name=persistCustomerSuccessMetrics]] launched with the following parameters: 
[{date=2015-12-12, -spring.batch.job.names=persistCustomerSuccessMetrics, run.id=2}]

The date 2015-12-12 is the date from first execution, and I'm not able to execute the job again with a different parameter.

My job setup:

@Bean
@JobScope
public CustomerSuccessMetricsReader customerSuccessMetricsReader(@Value("#{jobParameters[date]}") String date) {
    return new CustomerSuccessMetricsReader(storeStatisticsUrl, restTemplate, date);
}
@Bean
public CustomerSuccessMetricsProcessor customerSuccessMetricsProcessor() {
    return new CustomerSuccessMetricsProcessor();
}
@Bean
public Job persistCustomerSuccessMetrics(Step persistCustomerSuccessMetricsStep1) {
    return jobBuilderFactory.get("persistCustomerSuccessMetrics").incrementer(new RunIdIncrementer())
            .listener(new CustomerSuccessMetricsCompletionListener()).flow(persistCustomerSuccessMetricsStep1).end().build();
}
@Bean
public Step persistCustomerSuccessMetricsStep1() {
    return stepBuilderFactory.
            get("persistCustomerSuccessMetricsStep1").
            <CustomerSuccessMetricsDTO, CustomerSuccessMetricsDTO> chunk(10).
            reader(customerSuccessMetricsReader(null)).
            processor(customerSuccessMetricsProcessor()).
            //writer(customerSuccessMetricsWriter).
            build();
}

I've tried to remove the incrementer(new RunIdIncrementer()) In that case it works fine, but I'm not able to repeat de execution with the same parameters.

So, i need to implement this job with the following rqs:

I'll appreciate any help. Regards

Upvotes: 0

Views: 6726

Answers (4)

user20121408
user20121408

Reputation: 1

in my case I have to run the job periodically using scheduler so i have to return a new job instance every time it gets from spring context Job job = (Job) context.getBean("methodName");

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Job methodName() {
 String jobName =  "methodName" + System.currentTimeMillis();
    return jobBuilderFactory.get(jobName)
            .start(step1()).on("COMPLETED").
            to(step2()).end().build();
            
}

Upvotes: 0

Mahmoud Ben Hassine
Mahmoud Ben Hassine

Reputation: 31710

I've tried to remove the incrementer(new RunIdIncrementer()) In that case it works fine, but I'm not able to repeat de execution with the same parameters.

By design, it is not possible to re-run a job instance once it is complete (if you try to do it, a JobInstanceAlreadyCompleteException will be thrown). You can re-run the same instance if the last execution failed, but once it is complete, you cannot run it again. This is explained in details with an example here: https://docs.spring.io/spring-batch/4.0.x/reference/html/domain.html#jobinstance

The job must take execution parameter, and not the parameter stored in database

The job must support multiple executions with the same parameter.

What you can do is to continue using the RunIdIncrementer as you do it now but make the date a non-identifying parameter. This way, the run.id parameter will contribute to the identification of your job instance (and hence you will have a new instance each run) but the date parameter will not contribute to the identification of the job instance. Non-identifying job parameters should be prefixed with "-" (See javadoc of the DefaultJobParametersConverter).

Hope this helps.

Upvotes: 1

Johannes Seib
Johannes Seib

Reputation: 1

The problem is how getNexJobParameters is working. It takes the JobParameters of the last execution of the last(!) instance of the job and put this as input to the JobParameterIncrementer. This way usually the new instance will inherit the parameters of an in some sense arbitrary job instance. This will obviously include non-identifying parameters as well. You can override the old parameter value explicitly on the command line.

Upvotes: 0

bluesoft
bluesoft

Reputation: 21

[Background] I have the same issue in that I have a single parameter for my job that I pass on the command line as follows:

$ java -jar ./target/[java-executable-jar].jar file=[file-path]

I have noticed that on a fresh spring batch meta-database this works fine for the first time, after that if I ran with a different file, Spring Batch uses the file path that was stored in the batch repository meta-database.

I tried all of the above proposed solutions and none works, as it was stated. I used the ".incrementer(new RunIdIncrementer())", it didn't work in making the job execution unique. I also tried passing the file parameter as a non identifying parameter like this:

$ java -jar ./target/[java-executable-jar].jar --file=[file-path]

I also tried adding a timestamp parameter, it didn't help Also it didn't work.

This seems to be an issue in the batch version as according to the documentation I able to make the job execution unique and the job to use the new file (the file is different everytime, not the same one in the first run.

Finally I had to revert to a hack to force solving the issue for me which is as follows:

[Solution] force naming the job differently for every time the app is ran. This way:

@Bean
public Job sampleJob() throws Exception {
   String jobName = "sampleJob" + System.currentTimeMillis();
   return jobBuilderFactory.get(jobName)
      .incrementer(new RunIdIncrementer())
      .start(step1()).on("COMPLETED").to(successFileArchiveStep())
      .from(step1()).on("*").to(failureFileArchiveStep())
      .end()
      .build();
}

Upvotes: 2

Related Questions