From 7f0824b9dad12f6a2d96d7cfa5e2efd60bd58f03 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 5 May 2021 16:20:28 +0200 Subject: [PATCH] Fix job execution validation in SimpleJobRepository Before this commit, the logic that validates if a job instance is complete or not was based only on the size of previous parameters, without checking if they are identifying or not. This commit introduces a change that uses only identifying job parameters to identify a job instance and validate its previous executions. Issue #1221 --- .../support/SimpleJobRepository.java | 7 ++++-- .../SimpleJobRepositoryIntegrationTests.java | 22 ++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java index 89bf9e64b..c5743ea2c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2020 the original author or authors. + * Copyright 2006-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.JobParameter; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; @@ -132,7 +133,9 @@ public class SimpleJobRepository implements JobRepository { + "The last execution ended with a failure that could not be rolled back, " + "so it may be dangerous to proceed. Manual intervention is probably necessary."); } - if (execution.getJobParameters().getParameters().size() > 0 && (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED)) { + Collection allJobParameters = execution.getJobParameters().getParameters().values(); + long identifyingJobParametersCount = allJobParameters.stream().filter(JobParameter::isIdentifying).count(); + if (identifyingJobParametersCount > 0 && (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED)) { throw new JobInstanceAlreadyCompleteException( "A job instance already exists and is complete for parameters=" + jobParameters + ". If you want to run this job again, change the parameters."); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java index dc5539e1f..e2204bcd8 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2018 the original author or authors. + * Copyright 2008-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,6 +44,7 @@ import static org.junit.Assert.fail; * * @author Robert Kasanicky * @author Dimitrios Liapis + * @author Mahmoud Ben Hassine */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "/org/springframework/batch/core/repository/dao/sql-dao-test.xml") @@ -212,4 +213,23 @@ public class SimpleJobRepositoryIntegrationTests { assertEquals(stepExecution, jobExecution.getStepExecutions().iterator().next()); } + /* + * Create two job executions for the same job+parameters tuple. Should ignore + * non-identifying job parameters when identifying the job instance. + */ + @Transactional + @Test + public void testReExecuteWithSameJobParameters() throws Exception { + JobParameters jobParameters = new JobParametersBuilder() + .addString("name", "foo", false) + .toJobParameters(); + JobExecution jobExecution1 = jobRepository.createJobExecution(job.getName(), jobParameters); + jobExecution1.setStatus(BatchStatus.COMPLETED); + jobExecution1.setEndTime(new Date()); + jobRepository.update(jobExecution1); + JobExecution jobExecution2 = jobRepository.createJobExecution(job.getName(), jobParameters); + assertNotNull(jobExecution1); + assertNotNull(jobExecution2); + } + }