spring-batchspring-batch-tasklet

Spring batch run same job with different parameters


I'm having a spring batch job which runs when passed certain job params. Now I wanted to achieve is a super job which constructs list of job params and executes this batch job with different job param.

I'm using jobLauncher to trigger the batch job using different params

The error am facing is

java.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove @Transactional annotations from client).

The way by which am triggering the job is

fun runJobs(jobParams: List<JobParameters>): List<JobExecution> =
      jobParams.map { jobParam ->
        jobLauncher.run(someJob, jobParam)
      }

Is there an example to trigger same job with different job params programmatically ?


Solution

  • I was able to achieve the same using jobStep.

    private fun jobSteps(jobParams: List<JobParams>): List<Step> =
          jobParams.map { jobParam ->
            jobStep(
                JobParametersBuilder()
                    .addString("param1", jobParam.param1)
                    .addString("param2", jobParam.param2))
          }
    
    private fun jobStep(jobParameters: JobParameters): Step =
          stepBuilderFactory
              .get("step-{some-unique-name-to-identify-each-job}")
              .job(<Job which needs to be executed for different params>)
              .parametersExtractor { _: Job, _: StepExecution -> jobParameters } // Here we are passing parameters for each job.
              .build()
    

    First create job steps. Now we will have a list of steps. They are steps which are job steps, they need to be wired to a super job and also they are independent of each.

    private fun superJob(steps: List<Step>): Job {
        val jobBuilder: JobFlowBuilder =
    jobBuilderFactory["superJob"].flow(<put a dummy start step here>)
    
        return steps
            .fold(jobBuilder) { builder: FlowBuilder<FlowJobBuilder>, step: Step ->
              builder.on("*").to(step)
            }
            .end()
            .build()
      }
    

    Conditions:

    1. This will make sure to run the same job for different parameters when launched the super job from job launcher.
    2. This launches the job steps sequentially. If you're looking for running them in parallel, follow (https://stackoverflow.com/a/37549969/7275579).
    3. The super job needs to be started with a unique job parameter like current time milliseconds / date, so that on its next run, it should not return as job already exists or completed.