From 4b68ed3aacb74be658f94a6bdb8e27f1fb57d139 Mon Sep 17 00:00:00 2001 From: Chris Schaefer Date: Sun, 30 Sep 2012 14:34:43 -0400 Subject: [PATCH] BATCH-1666: Add abort(long executionId) convenience method to JobOperator --- .../batch/core/launch/JobOperator.java | 13 ++++++++++ .../launch/support/SimpleJobOperator.java | 18 ++++++++++++- .../support/SimpleJobOperatorTests.java | 26 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/JobOperator.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/JobOperator.java index 2c4427b5d..129203c47 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/JobOperator.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/JobOperator.java @@ -197,4 +197,17 @@ public interface JobOperator { */ Set getJobNames(); + /** + * Mark the {@link JobExecution} as ABANDONED. If a stop signal is ignored + * because the process died this is the best way to mark a job as finished + * with (as opposed to STOPPED). An abandoned job execution can be + * restarted, but a stopping one cannot. + * + * @param jobExecutionId the job execution id to abort + * @return the {@link JobExecution} that was aborted + * @throws NoSuchJobExecutionException + * @throws JobExecutionAlreadyRunningException if the job is running (it + * should be stopped first) + */ + JobExecution abandon(long jobExecutionId) throws NoSuchJobExecutionException, JobExecutionAlreadyRunningException; } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobOperator.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobOperator.java index a16e914f0..0556879b0 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobOperator.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobOperator.java @@ -16,6 +16,7 @@ package org.springframework.batch.core.launch.support; import java.util.ArrayList; +import java.util.Date; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -382,6 +383,22 @@ public class SimpleJobOperator implements JobOperator, InitializingBean { return true; } + public JobExecution abandon(long jobExecutionId) throws NoSuchJobExecutionException, JobExecutionAlreadyRunningException { + JobExecution jobExecution = findExecutionById(jobExecutionId); + + if (jobExecution.getStatus().isLessThan(BatchStatus.STOPPING)) { + throw new JobExecutionAlreadyRunningException( + "JobExecution is running or complete and therefore cannot be aborted"); + } + + logger.info("Aborting job execution: " + jobExecution); + jobExecution.upgradeStatus(BatchStatus.ABANDONED); + jobExecution.setEndTime(new Date()); + jobRepository.update(jobExecution); + + return jobExecution; + } + private JobExecution findExecutionById(long executionId) throws NoSuchJobExecutionException { JobExecution jobExecution = jobExplorer.getJobExecution(executionId); @@ -391,5 +408,4 @@ public class SimpleJobOperator implements JobOperator, InitializingBean { return jobExecution; } - } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/SimpleJobOperatorTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/SimpleJobOperatorTests.java index 157ed9a2e..03d7b0d8f 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/SimpleJobOperatorTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/SimpleJobOperatorTests.java @@ -20,6 +20,7 @@ import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -393,4 +394,29 @@ public class SimpleJobOperatorTests { assertEquals(BatchStatus.STOPPING, jobExecution.getStatus()); } + @Test + public void testAbort() throws Exception { + JobInstance jobInstance = new JobInstance(123L, jobParameters, job.getName()); + JobExecution jobExecution = new JobExecution(jobInstance, 111L); + jobExecution.setStatus(BatchStatus.STOPPING); + jobExplorer.getJobExecution(123L); + expectLastCall().andReturn(jobExecution); + jobRepository.update(jobExecution); + replay(jobExplorer); + jobOperator.abandon(123L); + assertEquals(BatchStatus.ABANDONED, jobExecution.getStatus()); + assertNotNull(jobExecution.getEndTime()); + } + + @Test(expected = JobExecutionAlreadyRunningException.class) + public void testAbortNonStopping() throws Exception { + JobInstance jobInstance = new JobInstance(123L, jobParameters, job.getName()); + JobExecution jobExecution = new JobExecution(jobInstance, 111L); + jobExecution.setStatus(BatchStatus.STARTED); + jobExplorer.getJobExecution(123L); + expectLastCall().andReturn(jobExecution); + jobRepository.update(jobExecution); + replay(jobExplorer); + jobOperator.abandon(123L); + } }