IN PROGRESS - issue BATCH-453: Killed batches cannot be restarted
http://jira.springframework.org/browse/BATCH-453 JobExecution now stores last updated time as well.
This commit is contained in:
@@ -42,6 +42,8 @@ public class JobExecution extends Entity {
|
||||
private volatile Date createTime = new Date(System.currentTimeMillis());
|
||||
|
||||
private volatile Date endTime = null;
|
||||
|
||||
private volatile Date lastUpdated = null;
|
||||
|
||||
private volatile ExitStatus exitStatus = ExitStatus.UNKNOWN;
|
||||
|
||||
@@ -222,4 +224,13 @@ public class JobExecution extends Entity {
|
||||
void addStepExecution(StepExecution stepExecution) {
|
||||
stepExecutions.add(stepExecution);
|
||||
}
|
||||
}
|
||||
|
||||
public Date getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
public void setLastUpdated(Date lastUpdated) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,28 +40,28 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
private static final int DEFAULT_EXIT_MESSAGE_LENGTH = 2500;
|
||||
|
||||
private static final String SAVE_JOB_EXECUTION = "INSERT into %PREFIX%JOB_EXECUTION(JOB_EXECUTION_ID, JOB_INSTANCE_ID, START_TIME, "
|
||||
+ "END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
+ "END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME, LAST_UPDATED) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String CHECK_JOB_EXECUTION_EXISTS = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?";
|
||||
|
||||
private static final String GET_STATUS = "SELECT STATUS from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID = ?";
|
||||
|
||||
private static final String UPDATE_JOB_EXECUTION = "UPDATE %PREFIX%JOB_EXECUTION set START_TIME = ?, END_TIME = ?, "
|
||||
+ " STATUS = ?, CONTINUABLE = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ? where JOB_EXECUTION_ID = ?";
|
||||
+ " STATUS = ?, CONTINUABLE = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ?, LAST_UPDATED = ? where JOB_EXECUTION_ID = ?";
|
||||
|
||||
private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION"
|
||||
+ " where JOB_INSTANCE_ID = ?";
|
||||
private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED" +
|
||||
" from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ?";
|
||||
|
||||
private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION"
|
||||
+ " where JOB_INSTANCE_ID = ? and CREATE_TIME = (SELECT max(CREATE_TIME) from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ?)";
|
||||
private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED " +
|
||||
"from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ? and CREATE_TIME = (SELECT max(CREATE_TIME) from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ?)";
|
||||
|
||||
private static final String GET_INSTANCE_BY_EXECUTION_ID = "SELECT JOB_INSTANCE_ID from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID = ?";
|
||||
|
||||
private static final String GET_EXECUTION_BY_ID = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION"
|
||||
+ " where JOB_EXECUTION_ID = ?";
|
||||
private static final String GET_EXECUTION_BY_ID = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED" +
|
||||
" from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID = ?";
|
||||
|
||||
private static final String GET_RUNNING_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, JOB_INSTANCE_ID from %PREFIX%JOB_EXECUTION"
|
||||
+ " where END_TIME is NULL";
|
||||
private static final String GET_RUNNING_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, " +
|
||||
"JOB_INSTANCE_ID from %PREFIX%JOB_EXECUTION where END_TIME is NULL";
|
||||
|
||||
private int exitMessageLength = DEFAULT_EXIT_MESSAGE_LENGTH;
|
||||
|
||||
@@ -142,12 +142,12 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
jobExecution.getStartTime(), jobExecution.getEndTime(), jobExecution.getStatus().toString(),
|
||||
jobExecution.getExitStatus().isContinuable() ? "Y" : "N", jobExecution.getExitStatus().getExitCode(),
|
||||
jobExecution.getExitStatus().getExitDescription(), jobExecution.getVersion(),
|
||||
jobExecution.getCreateTime() };
|
||||
jobExecution.getCreateTime(), jobExecution.getLastUpdated() };
|
||||
getJdbcTemplate().getJdbcOperations().update(
|
||||
getQuery(SAVE_JOB_EXECUTION),
|
||||
parameters,
|
||||
new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.CHAR,
|
||||
Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP });
|
||||
Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +187,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
Object[] parameters = new Object[] { jobExecution.getStartTime(), jobExecution.getEndTime(),
|
||||
jobExecution.getStatus().toString(), jobExecution.getExitStatus().isContinuable() ? "Y" : "N",
|
||||
jobExecution.getExitStatus().getExitCode(), exitDescription, jobExecution.getVersion(),
|
||||
jobExecution.getCreateTime(), jobExecution.getId() };
|
||||
jobExecution.getCreateTime(), jobExecution.getLastUpdated(), jobExecution.getId() };
|
||||
|
||||
if (jobExecution.getId() == null) {
|
||||
throw new IllegalArgumentException("JobExecution ID cannot be null. JobExecution must be saved "
|
||||
@@ -205,7 +205,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
getQuery(UPDATE_JOB_EXECUTION),
|
||||
parameters,
|
||||
new int[] { Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.CHAR, Types.VARCHAR, Types.VARCHAR,
|
||||
Types.INTEGER, Types.TIMESTAMP, Types.INTEGER });
|
||||
Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP, Types.INTEGER });
|
||||
}
|
||||
|
||||
public JobExecution getLastJobExecution(JobInstance jobInstance) {
|
||||
@@ -299,7 +299,8 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
jobExecution.setEndTime(rs.getTimestamp(3));
|
||||
jobExecution.setStatus(BatchStatus.valueOf(rs.getString(4)));
|
||||
jobExecution.setExitStatus(new ExitStatus("Y".equals(rs.getString(5)), rs.getString(6), rs.getString(7)));
|
||||
jobExecution.setCreateTime(rs.getDate(8));
|
||||
jobExecution.setCreateTime(rs.getTimestamp(8));
|
||||
jobExecution.setLastUpdated(rs.getTimestamp(9));
|
||||
return jobExecution;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,7 @@ public class SimpleJobRepository implements JobRepository {
|
||||
|
||||
JobExecution jobExecution = new JobExecution(jobInstance);
|
||||
jobExecution.setExecutionContext(executionContext);
|
||||
jobExecution.setLastUpdated(new Date(System.currentTimeMillis()));
|
||||
|
||||
// Save the JobExecution so that it picks up an ID (useful for clients
|
||||
// monitoring asynchronous executions):
|
||||
@@ -214,6 +215,7 @@ public class SimpleJobRepository implements JobRepository {
|
||||
Assert.notNull(jobExecution.getJobId(), "JobExecution must have a Job ID set.");
|
||||
Assert.notNull(jobExecution.getId(), "JobExecution must be already saved (have an id assigned).");
|
||||
|
||||
jobExecution.setLastUpdated(new Date(System.currentTimeMillis()));
|
||||
jobExecutionDao.updateJobExecution(jobExecution);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ CREATE TABLE BATCH_JOB_EXECUTION (
|
||||
STATUS VARCHAR(10) ,
|
||||
CONTINUABLE CHAR(1) ,
|
||||
EXIT_CODE VARCHAR(20) ,
|
||||
EXIT_MESSAGE VARCHAR(2500) ,
|
||||
EXIT_MESSAGE VARCHAR(2500) ,
|
||||
LAST_UPDATED TIMESTAMP ,
|
||||
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
|
||||
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
|
||||
) ;
|
||||
|
||||
@@ -50,11 +50,14 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
|
||||
@Test
|
||||
public void testSaveAndFind() {
|
||||
|
||||
execution.setStartTime(new Date(System.currentTimeMillis()));
|
||||
execution.setLastUpdated(new Date(System.currentTimeMillis()));
|
||||
dao.saveJobExecution(execution);
|
||||
|
||||
List<JobExecution> executions = dao.findJobExecutions(jobInstance);
|
||||
assertEquals(1, executions.size());
|
||||
assertEquals(execution, executions.get(0));
|
||||
assertExecutionsAreEqual(execution, executions.get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,12 +94,14 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
|
||||
execution.setStatus(BatchStatus.STARTED);
|
||||
dao.saveJobExecution(execution);
|
||||
|
||||
execution.setLastUpdated(new Date(0));
|
||||
execution.setStatus(BatchStatus.COMPLETED);
|
||||
dao.updateJobExecution(execution);
|
||||
|
||||
JobExecution updated = dao.findJobExecutions(jobInstance).get(0);
|
||||
assertEquals(execution, updated);
|
||||
assertEquals(BatchStatus.COMPLETED, updated.getStatus());
|
||||
assertExecutionsAreEqual(execution, updated);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,9 +141,11 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
|
||||
public void testFindRunningExecutions() {
|
||||
JobExecution exec = new JobExecution(jobInstance);
|
||||
exec.setCreateTime(new Date(0));
|
||||
exec.setEndTime(new Date(0));
|
||||
exec.setEndTime(new Date(1L));
|
||||
exec.setLastUpdated(new Date(5L));
|
||||
dao.saveJobExecution(exec);
|
||||
exec = new JobExecution(jobInstance);
|
||||
exec.setLastUpdated(new Date(5L));
|
||||
exec.createStepExecution(new StepSupport("foo"));
|
||||
dao.saveJobExecution(exec);
|
||||
StepExecutionDao stepExecutionDao = getStepExecutionDao();
|
||||
@@ -152,6 +159,7 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
|
||||
assertEquals(1, values.size());
|
||||
JobExecution value = values.iterator().next();
|
||||
assertEquals(exec, value);
|
||||
assertEquals(5L, value.getLastUpdated().getTime());
|
||||
assertEquals(1, value.getStepExecutions().size());
|
||||
}
|
||||
|
||||
@@ -198,4 +206,19 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
|
||||
assertNull(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to make sure the executions are equal. Normally, comparing the id's is
|
||||
* sufficient. However, for testing purposes, especially of a dao, we need to make
|
||||
* sure all the fields are being stored/retrieved correctly.
|
||||
*/
|
||||
private void assertExecutionsAreEqual(JobExecution lhs, JobExecution rhs){
|
||||
|
||||
assertEquals(lhs.getId(), rhs.getId());
|
||||
assertEquals(lhs.getStartTime(), rhs.getStartTime());
|
||||
assertEquals(lhs.getStatus(), rhs.getStatus());
|
||||
assertEquals(lhs.getEndTime(), rhs.getEndTime());
|
||||
assertEquals(lhs.getCreateTime(), rhs.getCreateTime());
|
||||
assertEquals(lhs.getLastUpdated(), rhs.getLastUpdated());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ public class SimpleJobRepositoryIntegrationTests {
|
||||
|
||||
JobExecution firstExecution = jobRepository.createJobExecution(job, jobParams);
|
||||
firstExecution.setStartTime(new Date());
|
||||
assertNotNull(firstExecution.getLastUpdated());
|
||||
|
||||
assertEquals(job.getName(), firstExecution.getJobInstance().getJobName());
|
||||
|
||||
|
||||
@@ -132,12 +132,13 @@ public class SimpleJobRepositoryTests {
|
||||
public void testUpdateValidJobExecution() throws Exception {
|
||||
|
||||
JobExecution jobExecution = new JobExecution(new JobInstance(new Long(1), jobParameters, job.getName()), new Long(1));
|
||||
|
||||
// new execution - call update on job dao
|
||||
jobExecutionDao.updateJobExecution(jobExecution);
|
||||
replay(jobExecutionDao);
|
||||
jobRepository.update(jobExecution);
|
||||
verify(jobExecutionDao);
|
||||
|
||||
assertNotNull(jobExecution.getLastUpdated());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user