BATCH-2311 JobLauncher allows restart of job_execution with status

UNKNOWN

* additionally prevent restart of step executions with status STARTING,
STARTED or STOPPING
* additionally prevent restart of job executions with status UNKNOWN or
STOPPING
This commit is contained in:
jpraet
2014-11-02 13:30:48 +01:00
committed by Michael Minella
parent 77be8b97b4
commit 61638d52bd
4 changed files with 81 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2014 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.
@@ -101,15 +101,21 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean {
throw new JobRestartException("JobInstance already exists and is not restartable");
}
/*
* validate here if it has stepExecutions that are UNKNOWN
* validate here if it has stepExecutions that are UNKNOWN, STARTING, STARTED and STOPPING
* retrieve the previous execution and check
*/
for (StepExecution execution : lastExecution.getStepExecutions()) {
if (execution.getStatus() == BatchStatus.UNKNOWN) {
//throw
throw new JobRestartException("Step [" + execution.getStepName() + "] is of status UNKNOWN");
}//end if
}//end for
BatchStatus status = execution.getStatus();
if (status.isRunning() || status == BatchStatus.STOPPING) {
throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: "
+ lastExecution);
} else if (status == BatchStatus.UNKNOWN) {
throw new JobRestartException(
"Cannot restart step [" + execution.getStepName() + "] from UNKNOWN status. "
+ "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.");
}
}
}
// Check the validity of the parameters before doing creating anything

View File

@@ -116,12 +116,16 @@ public class SimpleJobRepository implements JobRepository {
// check for running executions and find the last started
for (JobExecution execution : executions) {
if (execution.isRunning()) {
if (execution.isRunning() || execution.isStopping()) {
throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: "
+ jobInstance);
}
BatchStatus status = execution.getStatus();
if (status == BatchStatus.UNKNOWN) {
throw new JobRestartException("Cannot restart job from UNKNOWN status. "
+ "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)) {
throw new JobInstanceAlreadyCompleteException(
"A job instance already exists and is complete for parameters=" + jobParameters

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2014 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.
@@ -41,6 +41,7 @@ import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.DefaultJobParametersValidator;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.core.task.TaskExecutor;
@@ -274,8 +275,25 @@ public class SimpleJobLauncherTests {
*/
@Test(expected=JobRestartException.class)
public void testRunStepStatusUnknown() throws Exception {
//try and restart a job where the step execution is UNKNOWN
//setup
testRestartStepExecutionInvalidStatus(BatchStatus.UNKNOWN);
}
@Test(expected = JobExecutionAlreadyRunningException.class)
public void testRunStepStatusStarting() throws Exception {
testRestartStepExecutionInvalidStatus(BatchStatus.STARTING);
}
@Test(expected = JobExecutionAlreadyRunningException.class)
public void testRunStepStatusStarted() throws Exception {
testRestartStepExecutionInvalidStatus(BatchStatus.STARTED);
}
@Test(expected = JobExecutionAlreadyRunningException.class)
public void testRunStepStatusStopping() throws Exception {
testRestartStepExecutionInvalidStatus(BatchStatus.STOPPING);
}
private void testRestartStepExecutionInvalidStatus(BatchStatus status) throws Exception {
String jobName = "test_job";
JobRepository jobRepository = mock(JobRepository.class);
JobParameters parameters = new JobParametersBuilder().addLong("runtime", System.currentTimeMillis()).toJobParameters();
@@ -288,7 +306,7 @@ public class SimpleJobLauncherTests {
when(job.isRestartable()).thenReturn(true);
when(job.getJobParametersValidator()).thenReturn(validator);
when(jobRepository.getLastJobExecution(jobName, parameters)).thenReturn(jobExecution);
when(stepExecution.getStatus()).thenReturn(BatchStatus.UNKNOWN);
when(stepExecution.getStatus()).thenReturn(status);
when(jobExecution.getStepExecutions()).thenReturn(Arrays.asList(stepExecution));
//setup launcher
@@ -297,6 +315,5 @@ public class SimpleJobLauncherTests {
//run
jobLauncher.run(job, parameters);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2014 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.
@@ -25,6 +25,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.junit.Before;
@@ -37,6 +39,9 @@ import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.dao.JobInstanceDao;
@@ -92,7 +97,7 @@ public class SimpleJobRepositoryTests {
jobRepository = new SimpleJobRepository(jobInstanceDao, jobExecutionDao, stepExecutionDao, ecDao);
jobParameters = new JobParametersBuilder().toJobParameters();
jobParameters = new JobParametersBuilder().addString("bar", "test").toJobParameters();
job = new JobSupport();
job.setBeanName("RepositoryTest");
@@ -232,4 +237,37 @@ public class SimpleJobRepositoryTests {
assertTrue(jobRepository.isJobInstanceExists("foo", new JobParameters()));
}
@Test(expected = JobExecutionAlreadyRunningException.class)
public void testCreateJobExecutionAlreadyRunning() throws Exception {
jobExecution.setStatus(BatchStatus.STARTED);
jobExecution.setEndTime(null);
when(jobInstanceDao.getJobInstance("foo", new JobParameters())).thenReturn(jobInstance);
when(jobExecutionDao.findJobExecutions(jobInstance)).thenReturn(Arrays.asList(jobExecution));
jobRepository.createJobExecution("foo", new JobParameters());
}
@Test(expected = JobRestartException.class)
public void testCreateJobExecutionStatusUnknown() throws Exception {
jobExecution.setStatus(BatchStatus.UNKNOWN);
jobExecution.setEndTime(new Date());
when(jobInstanceDao.getJobInstance("foo", new JobParameters())).thenReturn(jobInstance);
when(jobExecutionDao.findJobExecutions(jobInstance)).thenReturn(Arrays.asList(jobExecution));
jobRepository.createJobExecution("foo", new JobParameters());
}
@Test(expected = JobInstanceAlreadyCompleteException.class)
public void testCreateJobExecutionAlreadyComplete() throws Exception {
jobExecution.setStatus(BatchStatus.COMPLETED);
jobExecution.setEndTime(new Date());
when(jobInstanceDao.getJobInstance("foo", new JobParameters())).thenReturn(jobInstance);
when(jobExecutionDao.findJobExecutions(jobInstance)).thenReturn(Arrays.asList(jobExecution));
jobRepository.createJobExecution("foo", new JobParameters());
}
}