RESOLVED - issue BATCH-1171: Interrupted step does not fail job.

Added check for STOPPED status in AbstractJob.
This commit is contained in:
dsyer
2009-03-23 10:52:55 +00:00
parent 6b1e440a67
commit 56de18f884
7 changed files with 213 additions and 27 deletions

View File

@@ -254,7 +254,7 @@ public abstract class AbstractJob implements Job, StepLocator, BeanNameAware, In
// The job was already stopped before we even got this far. Deal
// with it in the same way as any other interruption.
execution.setStatus(BatchStatus.FAILED);
execution.setStatus(BatchStatus.STOPPED);
execution.setExitStatus(ExitStatus.COMPLETED);
}
@@ -346,7 +346,7 @@ public abstract class AbstractJob implements Job, StepLocator, BeanNameAware, In
jobRepository.updateExecutionContext(execution);
if (currentStepExecution.getStatus() == BatchStatus.STOPPING) {
if (currentStepExecution.getStatus() == BatchStatus.STOPPING || currentStepExecution.getStatus() == BatchStatus.STOPPED) {
throw new JobInterruptedException("Job interrupted by step execution");
}

View File

@@ -341,26 +341,13 @@ public class SimpleJobTests {
"no steps configured") >= 0);
}
// public void testNoStepsExecuted() throws Exception {
// StepExecution completedExecution = new
// StepExecution("completedExecution", jobExecution);
// completedExecution.setStatus(BatchStatus.COMPLETED);
//
// job.execute(jobExecution);
// ExitStatus exitStatus = jobExecution.getExitStatus();
// assertEquals(ExitStatus.NOOP.getExitCode(), exitStatus.getExitCode());
// assertTrue("Wrong message in execution: " + exitStatus,
// exitStatus.getExitDescription().contains(
// "steps already completed"));
// }
@Test
public void testNotExecutedIfAlreadyStopped() throws Exception {
jobExecution.stop();
job.execute(jobExecution);
assertEquals(0, list.size());
checkRepository(BatchStatus.FAILED, ExitStatus.NOOP);
checkRepository(BatchStatus.STOPPED, ExitStatus.NOOP);
ExitStatus exitStatus = jobExecution.getExitStatus();
assertEquals(ExitStatus.NOOP.getExitCode(), exitStatus.getExitCode());
}
@@ -454,7 +441,7 @@ public class SimpleJobTests {
assertNull("Second step was not supposed to be executed", step2.passedInStepContext);
}
@Test
public void testGetStepExists() {
step1 = new StubStep("step1", jobRepository);
@@ -546,7 +533,7 @@ public class SimpleJobTests {
stepExecution.setExitStatus(ExitStatus.FAILED);
stepExecution.setStatus(BatchStatus.FAILED);
stepExecution.addFailureException(exception);
throw (JobInterruptedException)exception;
throw (JobInterruptedException) exception;
}
if (exception instanceof RuntimeException) {
stepExecution.setExitStatus(ExitStatus.FAILED);

View File

@@ -28,6 +28,7 @@ import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
@@ -38,7 +39,13 @@ import org.springframework.batch.core.job.flow.support.state.DecisionState;
import org.springframework.batch.core.job.flow.support.state.EndState;
import org.springframework.batch.core.job.flow.support.state.StepState;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.dao.MapExecutionContextDao;
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.core.repository.support.SimpleJobRepository;
import org.springframework.batch.core.step.StepSupport;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
@@ -53,15 +60,19 @@ public class FlowJobTests {
private JobExecution jobExecution;
private JobRepository jobRepository;
private boolean fail = false;
private JobExecutionDao jobExecutionDao;
@Before
public void setUp() throws Exception {
MapJobRepositoryFactoryBean.clear();
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.afterPropertiesSet();
jobExecutionDao = new MapJobExecutionDao();
jobRepository = new SimpleJobRepository(new MapJobInstanceDao(), jobExecutionDao, new MapStepExecutionDao(), new MapExecutionContextDao());
jobRepository = (JobRepository) factory.getObject();
job.setJobRepository(jobRepository);
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
@@ -181,6 +192,29 @@ public class FlowJobTests {
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
}
@Test
public void testInterrupted() throws Exception {
SimpleFlow flow = new SimpleFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
stepExecution.setStatus(BatchStatus.STOPPING);
jobRepository.update(stepExecution);
}
}), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
job.execute(jobExecution);
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
checkRepository(BatchStatus.STOPPED, ExitStatus.STOPPED);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(JobInterruptedException.class, jobExecution.getFailureExceptions().get(0).getClass());
}
@Test
public void testEndStateStopped() throws Exception {
SimpleFlow flow = new SimpleFlow("job");
@@ -418,4 +452,15 @@ public class FlowJobTests {
return null;
}
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
// because map dao stores in memory, it can be checked directly
JobInstance jobInstance = jobExecution.getJobInstance();
JobExecution other = (JobExecution) jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), other.getJobId());
assertEquals(status, other.getStatus());
if (exitStatus != null) {
assertEquals(exitStatus.getExitCode(), other.getExitStatus().getExitCode());
}
}
}

View File

@@ -115,4 +115,3 @@ Export-Package: org.springframework.batch.item;version="0",org.springf
support",org.springframework.batch.support.transaction;version="0";us
es:="org.aopalliance.intercept,org.springframework.transaction,org.sp
ringframework.transaction.support"

View File

@@ -7,6 +7,7 @@
<property name="dataSource" ref="dataSource"/>
<property name="initScripts">
<list>
<value>${batch.drop.script}</value>
<value>${batch.schema.script}</value>
<value>${batch.business.schema.script}</value>
</list>

View File

@@ -16,6 +16,7 @@
package org.springframework.batch.sample.launch;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -83,7 +84,7 @@ public class RemoteLauncherTests {
assertTrue(launcher.getJobNames().contains("loopJob"));
}
//@Test
@Test
public void testPauseJob() throws Exception {
final int SLEEP_INTERVAL = 600;
assertTrue(isConnected());
@@ -100,18 +101,19 @@ public class RemoteLauncherTests {
// assertEquals(0, launcher.getRunningExecutions("loopJob").size());
logger.debug(launcher.getSummary(executionId));
long resumedId = launcher.restart(executionId);
assertEquals("Picked up the same execution after pause and resume", executionId, resumedId);
assertNotSame("Picked up the same execution after pause and resume", executionId, resumedId);
Thread.sleep(SLEEP_INTERVAL);
launcher.stop(executionId);
launcher.stop(resumedId);
Thread.sleep(SLEEP_INTERVAL);
// assertEquals(0, launcher.getRunningExecutions("loopJob").size());
logger.debug(launcher.getSummary(executionId));
long resumeId2 = launcher.restart(executionId);
assertEquals("Picked up the same execution after pause and resume", executionId, resumeId2);
logger.debug(launcher.getSummary(resumedId));
long resumeId2 = launcher.restart(resumedId);
assertNotSame("Picked up the same execution after pause and resume", executionId, resumeId2);
launcher.stop(executionId);
Thread.sleep(SLEEP_INTERVAL);
launcher.stop(resumeId2);
}

View File

@@ -0,0 +1,152 @@
Spring Batch 2.0.0.RC2 Release Notes
* Issues
* {{{http://jira.springframework.org/browse/BATCH-1165}BATCH-1165}} - Allow 'id' and 'ref' to exist together on <*-listener/>
* {{{http://jira.springframework.org/browse/BATCH-1164}BATCH-1164}} - Putting scope="step" on a listener causes failure
* {{{http://jira.springframework.org/browse/BATCH-1163}BATCH-1163}} - In Batch xsd, elements in <job/> should be unordered
* {{{http://jira.springframework.org/browse/BATCH-1162}BATCH-1162}} - In Batch xsd, elements in <split/> should be unordered
* {{{http://jira.springframework.org/browse/BATCH-1161}BATCH-1161}} - Throw error if a flow has no steps
* {{{http://jira.springframework.org/browse/BATCH-1160}BATCH-1160}} - In Batch xsd, stepType and flowStepType should be unordered
* {{{http://jira.springframework.org/browse/BATCH-1159}BATCH-1159}} - PROCESS_SKIP_COUNT seems not to ever get written to database
* {{{http://jira.springframework.org/browse/BATCH-1157}BATCH-1157}} - Add max count parameter to counting item readers
* {{{http://jira.springframework.org/browse/BATCH-1154}BATCH-1154}} - TaskletElementParser can't predict which StepFactoryBean to use
* {{{http://jira.springframework.org/browse/BATCH-1153}BATCH-1153}} - listener element should only have an "id" when defined at the top level
* {{{http://jira.springframework.org/browse/BATCH-1152}BATCH-1152}} - Allow comma and newline as delimiters in exception lists in namespace
* {{{http://jira.springframework.org/browse/BATCH-1151}BATCH-1151}} - Add IDE support to <retry-listeners/> in xsd
* {{{http://jira.springframework.org/browse/BATCH-1147}BATCH-1147}} - StepExecution getFilterCount always return 0
* {{{http://jira.springframework.org/browse/BATCH-1145}BATCH-1145}} - Conflicts if both <step/> and <tasklet/> have a "parent" attribute
* {{{http://jira.springframework.org/browse/BATCH-1144}BATCH-1144}} - Create top-level element <job-listener/>
* {{{http://jira.springframework.org/browse/BATCH-1143}BATCH-1143}} - Standalone <step/> should not be allowed to have "tasklet" attribute and <tasklet/> together
* {{{http://jira.springframework.org/browse/BATCH-1142}BATCH-1142}} - In the xsd, <listeners/> should be moved from "flowType" to "job"
* {{{http://jira.springframework.org/browse/BATCH-1141}BATCH-1141}} - Rename CompositeExecutionJobListener to CompositeJobExecutionListener
* {{{http://jira.springframework.org/browse/BATCH-1139}BATCH-1139}} - Add "parent" attribute to <tasklet/>
* {{{http://jira.springframework.org/browse/BATCH-1138}BATCH-1138}} - Add "parent" attribute to <job/>
* {{{http://jira.springframework.org/browse/BATCH-1136}BATCH-1136}} - Add setListeners(StepExecutionListener[]) to TaskletStep
* {{{http://jira.springframework.org/browse/BATCH-1135}BATCH-1135}} - Create top-level element <step-listener/>
* {{{http://jira.springframework.org/browse/BATCH-1134}BATCH-1134}} - Create a superclass for StepListenerParser and JobExecutionListenerParser
* {{{http://jira.springframework.org/browse/BATCH-1132}BATCH-1132}} - Add "parent" attribute to <step/>
* {{{http://jira.springframework.org/browse/BATCH-1131}BATCH-1131}} - It is not possible to set transaction-attributes for a tasklet step
* {{{http://jira.springframework.org/browse/BATCH-1130}BATCH-1130}} - Ensure Ordered is respected by generated listeners
* {{{http://jira.springframework.org/browse/BATCH-1129}BATCH-1129}} - Problems with exception classifications
* {{{http://jira.springframework.org/browse/BATCH-1128}BATCH-1128}} - Make sure WRITE_COUNT and ROLLBACK_COUNT are being updated correctly
* {{{http://jira.springframework.org/browse/BATCH-1127}BATCH-1127}} - Add contextual line number information for exceptions thrown by FlatFileItemReader
* {{{http://jira.springframework.org/browse/BATCH-1126}BATCH-1126}} - StepScope does not apply to twice nested inner beans
* {{{http://jira.springframework.org/browse/BATCH-1125}BATCH-1125}} - NoWorkFoundStepExecutionListener doesn't fail the step
* {{{http://jira.springframework.org/browse/BATCH-1124}BATCH-1124}} - Fix error message that occurs when the same annotation is used twice on one method
* {{{http://jira.springframework.org/browse/BATCH-1123}BATCH-1123}} - ExecutionContextPromotionListener may perform promotion multiple times
* {{{http://jira.springframework.org/browse/BATCH-1122}BATCH-1122}} - StaxEventWriter.startDocument() needs to be protected
* {{{http://jira.springframework.org/browse/BATCH-1121}BATCH-1121}} - Documentation should cover the 'no work found' scenario
* {{{http://jira.springframework.org/browse/BATCH-1120}BATCH-1120}} - Allow completion policy to be set on step
* {{{http://jira.springframework.org/browse/BATCH-1119}BATCH-1119}} - afterWrite() will only be called if an exception is raised during throttling
* {{{http://jira.springframework.org/browse/BATCH-1118}BATCH-1118}} - Listener annotation with wrong signature fails too late and too quietly
* {{{http://jira.springframework.org/browse/BATCH-1117}BATCH-1117}} - onWriteError should be called with only the bad item
* {{{http://jira.springframework.org/browse/BATCH-1116}BATCH-1116}} - Create section on MetaDataInstanceFactory in testing chapter
* {{{http://jira.springframework.org/browse/BATCH-1113}BATCH-1113}} - query for JdbcJobExecutionDao.findRunningJobExecutions is broken
* {{{http://jira.springframework.org/browse/BATCH-1112}BATCH-1112}} - Remove cycle in infrastructure database/support
* {{{http://jira.springframework.org/browse/BATCH-1111}BATCH-1111}} - ChunkListener called before WriteListener
* {{{http://jira.springframework.org/browse/BATCH-1110}BATCH-1110}} - Defer EntityManager flushing and clearing in JpaPagingItemReader
* {{{http://jira.springframework.org/browse/BATCH-1109}BATCH-1109}} - Generalise PrefixMatching* to PatternMatching*
* {{{http://jira.springframework.org/browse/BATCH-1108}BATCH-1108}} - Add composite ItemWriter/Processor based on Classifier
* {{{http://jira.springframework.org/browse/BATCH-1107}BATCH-1107}} - Fix Date conversion in PlaceholderTargetSource
* {{{http://jira.springframework.org/browse/BATCH-1106}BATCH-1106}} - SqlPagingQueryProviderFactoryBean ascending should default to true
* {{{http://jira.springframework.org/browse/BATCH-1105}BATCH-1105}} - Namespace error in documentation
* {{{http://jira.springframework.org/browse/BATCH-1104}BATCH-1104}} - Wrong stax version in spring-batch-parent-2.0.0.RC1.pom, is 1.2 should be 1.2.0
* {{{http://jira.springframework.org/browse/BATCH-1103}BATCH-1103}} - Add partioning sample
* {{{http://jira.springframework.org/browse/BATCH-1102}BATCH-1102}} - Classes with "listener" annotations should be auto-registered
* {{{http://jira.springframework.org/browse/BATCH-1101}BATCH-1101}} - Remove StepScope bean definition from samples that don't need it
* {{{http://jira.springframework.org/browse/BATCH-1099}BATCH-1099}} - Make writer in skip sample stateful
* {{{http://jira.springframework.org/browse/BATCH-1098}BATCH-1098}} - Check @AfterWrite is only called once per item
* {{{http://jira.springframework.org/browse/BATCH-1097}BATCH-1097}} - Add late binding to some io samples
* {{{http://jira.springframework.org/browse/BATCH-1096}BATCH-1096}} - Add late binding to some io samples
* {{{http://jira.springframework.org/browse/BATCH-1093}BATCH-1093}} - Make AbstractJobTests.makeUniqueJobParameters() public
* {{{http://jira.springframework.org/browse/BATCH-1092}BATCH-1092}} - Fix naming conventions for exit status in <end/>
* {{{http://jira.springframework.org/browse/BATCH-1091}BATCH-1091}} - Add strict flag to file readers (flat and XML).
* {{{http://jira.springframework.org/browse/BATCH-1072}BATCH-1072}} - Update docs to reflect attribute change in step element
* {{{http://jira.springframework.org/browse/BATCH-1065}BATCH-1065}} - "BATCH-1011
* {{{http://jira.springframework.org/browse/Update documentation to explain end/fail/pause transitions"
* {{{http://jira.springframework.org/browse/BATCH-976}BATCH-976}} - Provide automatic batch database schema installation utility
* {{{http://jira.springframework.org/browse/BATCH-937}BATCH-937}} - Make sure JobRepository can be proxied
* {{{http://jira.springframework.org/browse/BATCH-935}BATCH-935}} - Use NumberFormat when parsing real numbers
* {{{http://jira.springframework.org/browse/BATCH-918}BATCH-918}} - Duplicate jar files in *-with-dependencies.zip
* {{{http://jira.springframework.org/browse/BATCH-902}BATCH-902}} - Revise FAQ on web site
* {{{http://jira.springframework.org/browse/BATCH-794}BATCH-794}} - Align with SpringSource Enterprise Repository
* {{{http://jira.springframework.org/browse/BATCH-632}BATCH-632}} - Move Tasklet interface from core to infrastructure
* {{{http://jira.springframework.org/browse/BATCH-573}BATCH-573}} - Delegating streams and listeners (e.g. HibernateAwareItemWriter) should delegate those interfaces to their delegates.
* {{{http://jira.springframework.org/browse/BATCH-501}BATCH-501}} - Core and Infrastructure still have circular dependency
* {{{http://jira.springframework.org/browse/BATCH-470}BATCH-470}} - RFC: Can all ExceptionHandlers be replaced by a combination of making Repeat/RetryListeners more robust and rewriting as Listeners?
* {{{http://jira.springframework.org/browse/BATCH-394}BATCH-394}} - If FieldSet is an interface it needs a factory, otherwise existing clients are tied to specific implementations
* {{{http://jira.springframework.org/browse/BATCH-22}BATCH-22}} - Find alternative to ThreadLocal for RepeatSynchronizationManager