Skip to content

Commit

Permalink
Make the meaning of running status consistent
Browse files Browse the repository at this point in the history
- A running status is STARTING, STARTED, or STOPPING.
- Update related tests.

 Resolves #1483
  • Loading branch information
lcmarvin authored and fmbenhassine committed Nov 17, 2022
1 parent 930bb02 commit bbf35b7
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 12 deletions.
Expand Up @@ -84,10 +84,10 @@ public static BatchStatus max(BatchStatus status1, BatchStatus status2) {

/**
* Convenience method to decide if a status indicates that work is in progress.
* @return true if the status is STARTING, STARTED
* @return true if the status is STARTING, STARTED, STOPPING
*/
public boolean isRunning() {
return this == STARTING || this == STARTED;
return this == STARTING || this == STARTED || this == STOPPING;
}

/**
Expand Down
Expand Up @@ -256,10 +256,11 @@ public StepExecution createStepExecution(String stepName) {
/**
* Test if this {@link JobExecution} indicates that it is running. Note that this does
* not necessarily mean that it has been persisted.
* @return {@code true} if the end time is null and the start time is not null.
* @return {@code true} if the status is one of the running statuses.
* @see BatchStatus#isRunning()
*/
public boolean isRunning() {
return startTime != null && endTime == null;
return status.isRunning();
}

/**
Expand Down
Expand Up @@ -119,7 +119,7 @@ public JobExecution run(final Job job, final JobParameters jobParameters)
*/
for (StepExecution execution : lastExecution.getStepExecutions()) {
BatchStatus status = execution.getStatus();
if (status.isRunning() || status == BatchStatus.STOPPING) {
if (status.isRunning()) {
throw new JobExecutionAlreadyRunningException(
"A job execution for this job is already running: " + lastExecution);
}
Expand Down
Expand Up @@ -88,7 +88,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
+ " from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID = ?";

private static final String GET_RUNNING_EXECUTIONS = "SELECT E.JOB_EXECUTION_ID, E.START_TIME, E.END_TIME, E.STATUS, E.EXIT_CODE, E.EXIT_MESSAGE, E.CREATE_TIME, E.LAST_UPDATED, E.VERSION, "
+ "E.JOB_INSTANCE_ID from %PREFIX%JOB_EXECUTION E, %PREFIX%JOB_INSTANCE I where E.JOB_INSTANCE_ID=I.JOB_INSTANCE_ID and I.JOB_NAME=? and E.START_TIME is not NULL and E.END_TIME is NULL order by E.JOB_EXECUTION_ID desc";
+ "E.JOB_INSTANCE_ID from %PREFIX%JOB_EXECUTION E, %PREFIX%JOB_INSTANCE I where E.JOB_INSTANCE_ID=I.JOB_INSTANCE_ID and I.JOB_NAME=? and E.STATUS in ('STARTING', 'STARTED', 'STOPPING') order by E.JOB_EXECUTION_ID desc";

private static final String CURRENT_VERSION_JOB_EXECUTION = "SELECT VERSION FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID=?";

Expand Down
Expand Up @@ -136,7 +136,7 @@ public JobExecution createJobExecution(String jobName, JobParameters jobParamete

// check for running executions and find the last started
for (JobExecution execution : executions) {
if (execution.isRunning() || execution.isStopping()) {
if (execution.isRunning()) {
throw new JobExecutionAlreadyRunningException(
"A job execution for this job is already running: " + jobInstance);
}
Expand Down
Expand Up @@ -71,6 +71,7 @@ void testIsRunning() {
assertFalse(BatchStatus.COMPLETED.isRunning());
assertTrue(BatchStatus.STARTED.isRunning());
assertTrue(BatchStatus.STARTING.isRunning());
assertTrue(BatchStatus.STOPPING.isRunning());
}

@Test
Expand Down
Expand Up @@ -56,14 +56,19 @@ void testGetEndTime() {
}

/**
* Test method for {@link org.springframework.batch.core.JobExecution#getEndTime()}.
* Test method for {@link org.springframework.batch.core.JobExecution#isRunning()}.
*/
@Test
void testIsRunning() {
LocalDateTime now = LocalDateTime.now();
execution.setStartTime(now);
execution.setStatus(BatchStatus.STARTING);
assertTrue(execution.isRunning());
execution.setStatus(BatchStatus.STARTED);
assertTrue(execution.isRunning());
execution.setEndTime(now.plus(10, ChronoUnit.SECONDS));
execution.setStatus(BatchStatus.STOPPING);
assertTrue(execution.isRunning());
execution.setStatus(BatchStatus.COMPLETED);
assertFalse(execution.isRunning());
execution.setStatus(BatchStatus.FAILED);
assertFalse(execution.isRunning());
}

Expand Down
Expand Up @@ -363,6 +363,7 @@ void testStepAlreadyComplete() throws Exception {
stepExecution1.setStatus(BatchStatus.COMPLETED);
jobRepository.add(stepExecution1);
jobExecution.setEndTime(LocalDateTime.now());
jobExecution.setStatus(BatchStatus.COMPLETED);
jobRepository.update(jobExecution);
jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters);
job.execute(jobExecution);
Expand Down
Expand Up @@ -204,6 +204,7 @@ void testFindRunningExecutions() {
exec.setCreateTime(now);
exec.setStartTime(now.plus(1, ChronoUnit.SECONDS));
exec.setEndTime(now.plus(2, ChronoUnit.SECONDS));
exec.setStatus(BatchStatus.COMPLETED);
exec.setLastUpdated(now.plus(3, ChronoUnit.SECONDS));
dao.saveJobExecution(exec);

Expand All @@ -215,9 +216,17 @@ void testFindRunningExecutions() {
exec.setLastUpdated(now.plus(3, ChronoUnit.SECONDS));
dao.saveJobExecution(exec);

// Stopping JobExecution as status is STOPPING
exec = new JobExecution(jobInstance, jobParameters);
exec.setStartTime(now.plus(6, ChronoUnit.SECONDS));
exec.setStatus(BatchStatus.STOPPING);
exec.setLastUpdated(now.plus(7, ChronoUnit.SECONDS));
dao.saveJobExecution(exec);

// Running JobExecution as StartTime is populated but EndTime is null
exec = new JobExecution(jobInstance, jobParameters);
exec.setStartTime(now.plus(2, ChronoUnit.SECONDS));
exec.setStatus(BatchStatus.STARTED);
exec.setLastUpdated(now.plus(3, ChronoUnit.SECONDS));
exec.createStepExecution("step");
dao.saveJobExecution(exec);
Expand All @@ -231,7 +240,7 @@ void testFindRunningExecutions() {

Set<JobExecution> values = dao.findRunningJobExecutions(exec.getJobInstance().getJobName());

assertEquals(1, values.size());
assertEquals(3, values.size());
JobExecution value = values.iterator().next();
assertEquals(exec, value);
assertEquals(now.plus(3, ChronoUnit.SECONDS), value.getLastUpdated());
Expand Down
Expand Up @@ -37,6 +37,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;

/**
* Repository tests using JDBC DAOs (rather than mocks).
Expand Down Expand Up @@ -76,6 +77,7 @@ void testCreateAndFind() throws Exception {
assertEquals(job.getName(), firstExecution.getJobInstance().getJobName());

jobRepository.update(firstExecution);
firstExecution.setStatus(BatchStatus.FAILED);
firstExecution.setEndTime(LocalDateTime.now());
jobRepository.update(firstExecution);
JobExecution secondExecution = jobRepository.createJobExecution(job.getName(), jobParams);
Expand All @@ -97,6 +99,7 @@ void testCreateAndFindWithNoStartDate() throws Exception {
LocalDateTime now = LocalDateTime.now();
firstExecution.setStartTime(now);
firstExecution.setEndTime(now.plus(1, ChronoUnit.SECONDS));
firstExecution.setStatus(BatchStatus.COMPLETED);
jobRepository.update(firstExecution);
JobExecution secondExecution = jobRepository.createJobExecution(job.getName(), jobParameters);

Expand Down Expand Up @@ -224,4 +227,48 @@ void testReExecuteWithSameJobParameters() throws Exception {
assertNotNull(jobExecution2);
}

/*
* When a job execution is running, JobExecutionAlreadyRunningException should be
* thrown if trying to create any other ones with same job parameters.
*/
@Transactional
@Test
public void testReExecuteWithSameJobParametersWhenRunning() throws Exception {
JobParameters jobParameters = new JobParametersBuilder().addString("stringKey", "stringValue")
.toJobParameters();

// jobExecution with status STARTING
JobExecution jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters);
try {
jobRepository.createJobExecution(job.getName(), jobParameters);
fail();
}
catch (JobExecutionAlreadyRunningException e) {
// expected
}

// jobExecution with status STARTED
jobExecution.setStatus(BatchStatus.STARTED);
jobExecution.setStartTime(LocalDateTime.now());
jobRepository.update(jobExecution);
try {
jobRepository.createJobExecution(job.getName(), jobParameters);
fail();
}
catch (JobExecutionAlreadyRunningException e) {
// expected
}

// jobExecution with status STOPPING
jobExecution.setStatus(BatchStatus.STOPPING);
jobRepository.update(jobExecution);
try {
jobRepository.createJobExecution(job.getName(), jobParameters);
fail();
}
catch (JobExecutionAlreadyRunningException e) {
// expected
}
}

}
Expand Up @@ -163,6 +163,7 @@ public boolean isRestartable() {
assertEquals("FOO", stepExecution.getFailureExceptions().get(0).getMessage());
JobExecution jobExecution = stepExecution.getJobExecution();
jobExecution.setEndTime(LocalDateTime.now());
jobExecution.setStatus(BatchStatus.FAILED);
jobRepository.update(jobExecution);

jobExecution = jobRepository.createJobExecution("job", new JobParameters());
Expand Down
Expand Up @@ -24,6 +24,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
Expand Down Expand Up @@ -84,6 +85,7 @@ void testRemoveJobExecutionsWithSameJobInstance() throws Exception {
List<JobExecution> list = new ArrayList<>();
JobExecution jobExecution = jobRepository.createJobExecution("job", new JobParameters());
jobExecution.setEndTime(LocalDateTime.now());
jobExecution.setStatus(BatchStatus.COMPLETED);
list.add(jobExecution);
jobRepository.update(jobExecution);
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
Expand Down

0 comments on commit bbf35b7

Please sign in to comment.