diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/StepHandlerStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/StepHandlerStep.java index a82f22a13..af0317609 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/StepHandlerStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/StepHandlerStep.java @@ -304,8 +304,15 @@ public class StepHandlerStep extends AbstractStep { logger.error("Fatal error detected during commit."); throw new FatalException("Fatal error detected during commit", e); } - - getJobRepository().update(stepExecution); + + try { + getJobRepository().update(stepExecution); + } + catch (Exception e) { + fatalException.setException(e); + stepExecution.setStatus(BatchStatus.UNKNOWN); + throw new FatalException("Fatal error detected during update of step execution", e); + } } catch (Error e) { diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepHandlerStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepHandlerStepTests.java index 9900805d3..635ce91f3 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepHandlerStepTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepHandlerStepTests.java @@ -35,6 +35,7 @@ import org.springframework.batch.core.StepExecutionListener; import org.springframework.batch.core.UnexpectedJobExecutionException; import org.springframework.batch.core.job.JobSupport; import org.springframework.batch.core.listener.StepExecutionListenerSupport; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.dao.MapExecutionContextDao; import org.springframework.batch.core.repository.dao.MapJobExecutionDao; import org.springframework.batch.core.repository.dao.MapJobInstanceDao; @@ -59,6 +60,7 @@ import org.springframework.batch.repeat.policy.DefaultResultCompletionPolicy; import org.springframework.batch.repeat.policy.SimpleCompletionPolicy; import org.springframework.batch.repeat.support.RepeatTemplate; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.transaction.TransactionException; import org.springframework.transaction.support.DefaultTransactionStatus; @@ -135,6 +137,9 @@ public class StepHandlerStepTests extends TestCase { assertEquals(1, stepExecution.getItemCount()); } + /** + * StepExecution should be updated after every chunk commit. + */ public void testStepExecutionUpdates() throws Exception { JobExecution jobExecution = new JobExecution(jobInstance); @@ -152,6 +157,31 @@ public class StepHandlerStepTests extends TestCase { assertTrue(3 <= jobRepository.updateCount); } + /** + * Failure to update StepExecution after chunk commit is fatal. + */ + public void testStepExecutionUpdateFailure() throws Exception { + + JobExecution jobExecution = new JobExecution(jobInstance); + StepExecution stepExecution = new StepExecution(step.getName(), jobExecution); + + JobRepository repository = new JobRepositoryFailedUpdateStub(); + + step.setJobRepository(repository); + step.afterPropertiesSet(); + + try { + step.execute(stepExecution); + fail(); + } + catch (Exception e) { + assertEquals(BatchStatus.UNKNOWN, stepExecution.getStatus()); + assertEquals("Fatal error detected during update of step execution", e.getMessage()); + assertEquals("stub exception", e.getCause().getMessage()); + } + + } + public void testChunkExecutor() throws Exception { RepeatTemplate template = new RepeatTemplate(); @@ -810,8 +840,21 @@ public class StepHandlerStepTests extends TestCase { } } + + private static class JobRepositoryFailedUpdateStub extends JobRepositorySupport { + + private boolean firstCall = true; + + public void update(StepExecution stepExecution) { + if (firstCall) { + firstCall = false; + throw new DataAccessResourceFailureException("stub exception"); + } + } + } - private class MockRestartableItemReader extends ItemStreamSupport implements ItemReader, StepExecutionListener { + private class MockRestartableItemReader extends ItemStreamSupport implements ItemReader, + StepExecutionListener { private boolean getExecutionAttributesCalled = false;