Spring Batch requires unique job parameters for its execution.so you can add the current time as a job parameter

Map<String, JobParameter> confMap = new HashMap<String, JobParameter>();
confMap.put("time", new JobParameter(System.currentTimeMillis()));
JobParameters jobParameters = new JobParameters(confMap);
jobLauncher.run(springCoreJob, jobParameters);
Answer from Jijo on Stack Overflow
🌐
GitHub
github.com › spring-projects › spring-batch › issues › 784
restart a completed job with same parameters [BATCH-2830] · Issue #784 · spring-projects/spring-batch
July 12, 2019 - JunGyun Lee opened BATCH-2830 and commented is it possible to restart the completed job with same parameters in spring-batch? I customized spring-batch framework to accept the user request. (restarting a completed job with same parameter...
Author   spring-projects
🌐
GitHub
github.com › spring-projects › spring-batch › issues › 882
Existing failed job is restarted, even if new job contains different job parameters [BATCH-2711] · Issue #882 · spring-projects/spring-batch
April 17, 2018 - After this a new job is started with the same job name, but different parameters: parm=1 fileName=new.csv. What happens is that Spring Batch restart the failed job with the errors again. Even if the new job contains different parameters. This worked perfectly as expected in version 3.0.8, but the issue occurred when upgraded to version 4.0.1.
Author   spring-projects
Top answer
1 of 2
3

We had the same issue and to me this looks like a flaw, especially when you compare how the SimpleJobLauncher evaluates the last job.

As you mentioned, getLasFailedJobExecution() does not take into account the parameters. (Which, at least in my opinion, is wrong. You can run the same job with different identifying parameters, but restarting would only work if only one of this runs failed.)

On the other hand, SimpleJobLauncher gets the last jobexecution based on the parameters:

public JobExecution run(final Job job, final JobParameters jobParameters)
        throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
        JobParametersInvalidException {
...

    JobExecution lastExecution = jobRepository.getLastJobExecution(job.getName(), jobParameters);
...

This is not consistent.

The way we fixed it was to implement our own CommandLineJobRunner that is derived from the CommandLineJobRunner, but you have to overwrite the whole start method and, therefore, you alse will have to copy a couple of private methods.

The whole restart part in the start method has to be changed in something like this:

        if (opts.contains("-restart")) {
            JobExecution lastExecution = jobRepository.getLastJobExecution(job.getName(), jobParameters);

            if (!jobExecution.getStatus().isGreaterThan(BatchStatus.STOPPING)) {
                throw new JobExecutionNotFailedException("No failed or stopped execution found for job="
                        + jobIdentifier);
            }
            jobParameters = jobExecution.getJobParameters();
            jobName = jobExecution.getJobInstance().getJobName();
        }

Edited

Sometimes I really should read the javadoc...

In case of a restart, you could pass the executionid instead of the jobname. In this case, it will find the right execution to restart.

From the javadoch of the main method:

restart: (optional) if the job has failed or stopped and the most should be restarted. If specified then the jobIdentifier parameter can be interpreted either as the name of the job or the id of the job execution that failed.

Therefore, using the execution id in case of a restart will ensure that the right instance is restarted. In this case, you also don't have to provide any other parameters, since they will be taken from the last execution.

2 of 2
0

If you pass the same set of parameters for a second time to the CommandLineJobRunner - the job will be restarted at the point of failure.

The option '-restart' is an additional short cut provided to restart certain types of run (e.g. last failed run)

🌐
Terasoluna-batch
terasoluna-batch.github.io › guideline › 5.0.0.RELEASE › en › Ch06_ReProcessing.html
Restart processing
Execute the failed job again with the same condition (same parameter). In Spring Batch, if you execute a job with the same parameters, it will be treated as double execution, but TERASOLUNA Batch 5.x treats it as a separate job For details,please referAbout parameter conversion class.
🌐
Coderanch
coderanch.com › t › 648318 › frameworks › spring-batch-job-restartable-job
How to make spring batch job restartable and job parameters unique (Spring forum at Coderanch)
April 6, 2015 - Directory may contain multiple files with a specific extenstion and i am using MultiResourceItemReader to read the files. Job will receive 3 job parameters as read_from_directory, move_to_directory and a default_user_id. All these parameters will remain same for all the job runs.
Top answer
1 of 3
3

Just to recap what was actually done based on the advice provided by incomplete-co.de. I created a recovery flow which is similar to the one below. The recovery flow wraps my actual batch and responsible only to serve the correct job parameters to the internal job. It could be initial parameters on first execution, new parameters on normal execution or old parameters in case the last execution had failed.

<batch:job id="recoveryWrapper"
       incrementer="wrapperRunIdIncrementer"
       restartable="true">
    <batch:decision id="recoveryFlowDecision" decider="recoveryFlowDecider">
        <batch:next on="FIRST_RUN" to="defineParametersOnFirstRun" />
        <batch:next on="RECOVER" to="recover.batchJob " />
        <batch:next on="CURRENT" to="current.batchJob " />
    </batch:decision>
    <batch:step id="defineParametersOnFirstRun" next="current.batchJob">
        <batch:tasklet ref="defineParametersOnFirstRunTasklet"/>
    </batch:step>
    <batch:step id="recover.batchJob " next="current.batchJob">
        <batch:job ref="batchJob" job-launcher="jobLauncher"
                            job-parameters-extractor="jobParametersExtractor" />
    </batch:step>
    <batch:step id="current.batchJob" >
       <batch:job ref="batchJob" job-launcher="jobLauncher"
                            job-parameters-extractor="jobParametersExtractor" />
    </batch:step>
</batch:job>

The heart of the solution is the RecoveryFlowDecider the JobParametersExtractor while using Spring Batch Restart mechanism. RecoveryFlowDecider will query the JobExplorer and JobRepository to find out if we had a failure in the last run. It will place The last execution on the execution context of the wrapper to use later in the JobParametersExtractor. Note the use of runIdIncremeter to allow re-execution of the wrapper job.

@Component
 public class RecoveryFlowDecider implements JobExecutionDecider {
        private static final String FIRST_RUN = "FIRST_RUN";
        private static final String CURRENT = "CURRENT";
        private static final String RECOVER = "RECOVER";

        @Autowired
        private JobExplorer jobExplorer;
        @Autowired
        private JobRepository jobRepository;

        @Override
        public FlowExecutionStatus decide(JobExecution jobExecution
                                         ,StepExecution stepExecution) {
            // the wrapper is named as the wrapped job + WRAPPER
            String wrapperJobName = jobExecution.getJobInstance().getJobName();
            String jobName;
             jobName = wrapperJobName.substring(0,wrapperJobName.indexOf(EtlConstants.WRAPPER));
            List<JobInstance> instances = jobExplorer.getJobInstances(jobName, 0, 1);
                JobInstance internalJobInstance = instances.size() > 0 ? instances.get(0) : null;

            if (null == internalJobInstance) {
                return new FlowExecutionStatus(FIRST_RUN);
            }
            JobExecution lastExecution = jobRepository.getLastJobExecution(internalJobInstance.getJobName()
    ,internalJobInstance.getJobParameters());
            //place the last execution on the context (wrapper context to use later)
            jobExecution.getExecutionContext().put(EtlConstants.LAST_EXECUTION, lastExecution);
                ExitStatus exitStatus = lastExecution.getExitStatus();

            if (ExitStatus.FAILED.equals(exitStatus) || ExitStatus.UNKNOWN.equals(exitStatus)) {
                return new FlowExecutionStatus(RECOVER);
            }else if(ExitStatus.COMPLETED.equals(exitStatus)){
                return new FlowExecutionStatus(CURRENT);    
            }
            //We should never get here unless we have a defect
            throw new RuntimeException("Unexpecded batch status: "+exitStatus+" in decider!");

        }

}

Then the JobParametersExtractor will test again for the outcome of the last execution, in case of failed job it will serve the original parameters used to execute the failed job triggering Spring Bacth restart mechanism. Otherwise it will create a new set of parameters and will execute at his normal course.

    @Component
    public class JobExecutionWindowParametersExtractor implements
            JobParametersExtractor {
        @Override
        public JobParameters getJobParameters(Job job, StepExecution stepExecution) {

            // Read the last execution from the wrapping job
            // in order to build Next Execution Window
            JobExecution lastExecution= (JobExecution) stepExecution.getJobExecution().getExecutionContext().get(EtlConstants.LAST_EXECUTION);;

            if(null!=lastExecution){
                if (ExitStatus.FAILED.equals(lastExecution.getExitStatus())) {
                    JobInstance instance = lastExecution.getJobInstance();
                    JobParameters parameters = instance.getJobParameters();                 
                                return parameters;
                }
            }       
            //We do not have failed execution or have no execution at all we need to create a new execution window
            return buildJobParamaters(lastExecution,stepExecution);
        }
...
}
2 of 3
2

have you considered a JobStep? that is, a step determines if there are any additional jobs to be run. this value is set into the StepExecutionContext. a JobExecutionDecider then checks for this value; if exists, directs to a JobStep which launches the Job.

here's the doc on it http://docs.spring.io/spring-batch/reference/htmlsingle/#external-flows

🌐
CodingNomads
codingnomads.com › spring-batch-tutorial-part-2
Spring Batch Tutorial Part 2: JobLauncher Batch Processing
Do you know why that was used? This parameter is your job identifier, which will cause Spring Batch to run the same job with the exact same parameters. You actually restarted the job as you tried the same URL a second time in the browser.
Find elsewhere
🌐
Baeldung
baeldung.com › home › spring › spring boot › restart a job on failure and continue in spring batch
Restart a Job on Failure and Continue in Spring Batch | Baeldung
September 3, 2025 - We need the file-based H2 database to enable job restartability by persisting job execution state across application runs. In this section, we’ll explore a Spring Batch job configuration that demonstrates a simple batch processing workflow. We’ll define a job with one step: processing a CSV file.
🌐
GitHub
github.com › spring-projects › spring-batch › issues › 1143
Restart failed job with job parameters [BATCH-2459] · Issue #1143 · spring-projects/spring-batch
December 13, 2015 - Edited Debugging the CommandLineJobRunner i found this code which always restarts the latest failed job irrespective of job parameters · private JobExecution getLastFailedJobExecution(String jobIdentifier) { List<JobExecution> jobExecutions = getJobExecutionsWithStatusGreaterThan(jobIdentifier, BatchStatus.STOPPING); if (jobExecutions.isEmpty()) { return null; } return jobExecutions.get(0); } Cant we expect spring batch to restart the failed job considering the job parameters some thing like this
Author   spring-projects
🌐
DEV Community
dev.to › sadiul_hakim › spring-batch-tutorial-part-4-20dl
Spring Batch Tutorial Part #4 - DEV Community
September 16, 2025 - Restartability is a core feature of Spring Batch. However, there are some rules: Successful Jobs Are Not Restartable: By default, if a JobInstance (identified by its parameters) has a final ExitStatus of COMPLETED, Spring Batch will throw a JobExecutionException if you try to run it again.
🌐
Spring
docs.spring.io › spring-batch › docs › 3.0.x › reference › html › configureJob.html
4. Configuring and Running a Job
This is to ensure that the batch meta data, including state that is necessary for restarts after a failure, is persisted correctly. The behavior of the framework is not well defined if the repository methods are not transactional. The isolation level in the create* method attributes is specified separately to ensure that when jobs are launched, if two processes are trying to launch the same ...
Top answer
1 of 3
10

It seems you have to configure the following beans to be able to restart your job.

@Bean
public JobOperator jobOperator(final JobLauncher jobLauncher, final JobRepository jobRepository,
        final JobRegistry jobRegistry, final JobExplorer jobExplorer) {
    final SimpleJobOperator jobOperator = new SimpleJobOperator();
    jobOperator.setJobLauncher(jobLauncher);
    jobOperator.setJobRepository(jobRepository);
    jobOperator.setJobRegistry(jobRegistry);
    jobOperator.setJobExplorer(jobExplorer);
    return jobOperator;
}

@Bean
public JobExplorer jobExplorer(final DataSource dataSource) throws Exception {
    final JobExplorerFactoryBean bean = new JobExplorerFactoryBean();
    bean.setDataSource(dataSource);
    bean.setTablePrefix("BATCH_");
    bean.setJdbcOperations(new JdbcTemplate(dataSource));
    bean.afterPropertiesSet();
    return bean.getObject();
}

Then you need to retrieve the batch instance id from the batch tables to be able to restart that specific instance by using the jobOperator.

final Long restartId = jobOperator.restart(id);
final JobExecution restartExecution = jobExplorer.getJobExecution(restartId);
2 of 3
4

Inside your JobManager class , instead of using JobLauncher , use JobOperator.restart() nethod .

The reason why your job is not getting restarted from the last failed step is because with JobLauncher you are again starting one more new job and hence it is starting the job from the step one .

Please make sure that "restartable" property is set to true (By default it is set to true ) .

Here is the sample code .

public boolean resumeWorkflow(long executionId)
        throws WorkflowResumeServiceException {
    JobOperator jobOperator = (JobOperator) ApplicationContextProvider.getApplicationContext().getBean("jobOperator");


    try 
    {

        LOGGER.info("SUMMARY AFTER RESTART:" + jobOperator.getSummary(executionId));
        jobOperator.restart(executionId);
    }
}

You need to get the jobExecutionid of the failed job and pass it to the above method .

Please note that a job which is completed with "FINISHED" status can not be restarted .

You can read this post also Restarting a job

🌐
Arnoldgalovics
arnoldgalovics.com › spring-batch-manager-failure
Handling manager failures in Spring Batch – Arnold Galovics
May 4, 2022 - The idea is to make Spring Batch believe that the manager job failed even though the partitions that it created were successfully processed. And then, we can restart the original job with the same parameters and Spring Batch will recognize “oh well, all the partitions have completed so nothing to do here”.
🌐
Spring
docs.spring.io › spring-batch › reference › step › chunk-oriented-processing › restart.html
Configuring a Step for Restart :: Spring Batch Reference
The preceding example configuration is for a job that loads in information about football games and summarizes them. It contains three steps: playerLoad, gameLoad, and playerSummarization. The playerLoad step loads player information from a flat file, while the gameLoad step does the same for games.
🌐
GitHub
github.com › spring-projects › spring-batch › discussions › 4694
Why Spring batch allows job without parameters to restart even if the job already completed successfullly? · spring-projects/spring-batch · Discussion #4694
No matter what the user provides, if the set of identifying job parameters ends up being the same (ie same hash), then the same job instance should not be restarted if it was completed in the previous run.
Author   spring-projects
🌐
Stack Overflow
stackoverflow.com › questions › 49916602 › spring-boot-batch-always-restart-the-failed-job-even-with-new-job-parameters
java - Spring Boot Batch always restart the failed job even with new job parameters - Stack Overflow
April 19, 2018 - This method gets the previous job's job parameters and the add the current job's parameters to the map. This means if the parameter values are the same, the current job's parameters are used.