BATCH-2009 - Stoppable tasklet

* Added the StoppableTasklet interface (an extension of the Tasklet interface).
* Updated JobOperator#stop(long executionId) to call StoppableTasklet#stop() on any currently running tasklets (local executions only).
* Updated the SystemCommandTasklet to implement StoppableTasklet
This commit is contained in:
willschipp
2013-05-22 07:34:57 -04:00
committed by Michael Minella
parent dbc829273b
commit 81e0c38d52
6 changed files with 219 additions and 3 deletions

View File

@@ -19,10 +19,12 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -35,12 +37,17 @@ import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.job.AbstractJob;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.launch.JobInstanceAlreadyExistsException;
import org.springframework.batch.core.launch.JobLauncher;
@@ -51,6 +58,10 @@ import org.springframework.batch.core.repository.JobExecutionAlreadyRunningExcep
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.StoppableTasklet;
import org.springframework.batch.core.step.tasklet.TaskletStep;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.batch.support.PropertiesConverter;
/**
@@ -254,6 +265,7 @@ public class SimpleJobOperatorTests {
}
@Test
@SuppressWarnings("unchecked")
public void testFindRunningExecutionsNoSuchJob() throws Exception {
jobParameters = new JobParameters();
when(jobExplorer.findRunningJobExecutions("no-such-job")).thenReturn(Collections.EMPTY_SET);
@@ -348,6 +360,67 @@ public class SimpleJobOperatorTests {
assertEquals(BatchStatus.STOPPING, jobExecution.getStatus());
}
@Test
public void testStopTasklet() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
StoppableTasklet tasklet = mock(StoppableTasklet.class);
TaskletStep taskletStep = new TaskletStep();
taskletStep.setTasklet(tasklet);
MockJob job = new MockJob();
job.taskletStep = taskletStep;
JobRegistry jobRegistry = mock(JobRegistry.class);
TaskletStep step = mock(TaskletStep.class);
when(step.getTasklet()).thenReturn(tasklet);
when(step.getName()).thenReturn("test_job.step1");
when(jobRegistry.getJob(anyString())).thenReturn(job);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobOperator.setJobRegistry(jobRegistry);
jobExplorer.getJobExecution(111L);
jobRepository.update(jobExecution);
jobOperator.stop(111L);
assertEquals(BatchStatus.STOPPING, jobExecution.getStatus());
}
@Test
public void testStopTaskletException() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
StoppableTasklet tasklet = new StoppableTasklet() {
@Override
public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
return null;
}
@Override
public void stop() {
throw new IllegalStateException();
}};
TaskletStep taskletStep = new TaskletStep();
taskletStep.setTasklet(tasklet);
MockJob job = new MockJob();
job.taskletStep = taskletStep;
JobRegistry jobRegistry = mock(JobRegistry.class);
TaskletStep step = mock(TaskletStep.class);
when(step.getTasklet()).thenReturn(tasklet);
when(step.getName()).thenReturn("test_job.step1");
when(jobRegistry.getJob(anyString())).thenReturn(job);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobOperator.setJobRegistry(jobRegistry);
jobExplorer.getJobExecution(111L);
jobRepository.update(jobExecution);
jobOperator.stop(111L);
assertEquals(BatchStatus.STOPPING, jobExecution.getStatus());
}
@Test
public void testAbort() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
@@ -369,4 +442,25 @@ public class SimpleJobOperatorTests {
jobRepository.update(jobExecution);
jobOperator.abandon(123L);
}
class MockJob extends AbstractJob {
private TaskletStep taskletStep;
@Override
public Step getStep(String stepName) {
return taskletStep;
}
@Override
public Collection<String> getStepNames() {
return Arrays.asList("test_job.step1");
}
@Override
protected void doExecute(JobExecution execution) throws JobExecutionException {
}
}
}

View File

@@ -221,6 +221,26 @@ public class SystemCommandTaskletIntegrationTests {
tasklet.setWorkingDirectory(directory.getCanonicalPath());
}
/*
* test stopping a tasklet
*/
@Test
public void testStopped() throws Exception {
String command = System.getProperty("os.name").toLowerCase().indexOf("win") >= 0 ?
"ping 1.1.1.1 -n 1 -w 5000" :
"sleep 5";
tasklet.setCommand(command);
tasklet.setTerminationCheckInterval(10);
tasklet.afterPropertiesSet();
StepContribution contribution = stepExecution.createStepContribution();
//send stop
tasklet.stop();
tasklet.execute(contribution, null);
assertEquals(contribution.getExitStatus().getExitCode(),ExitStatus.STOPPED.getExitCode());
}
/**
* Exit code mapper containing mapping logic expected by the tests. 0 means
* finished successfully, other value means failure.