diff --git a/pom.xml b/pom.xml index 2a4de1e4..2b2ef2cc 100755 --- a/pom.xml +++ b/pom.xml @@ -71,8 +71,8 @@ spring-cloud-task-batch spring-cloud-task-stream spring-cloud-task-starter - spring-cloud-task-integration-tests spring-cloud-task-samples + spring-cloud-task-integration-tests diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java index 42c2694a..1a9d9f1a 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java @@ -156,7 +156,7 @@ public class TaskLifecycleListener implements ApplicationListener arguments) { + String exitMessage, List arguments, + String errorMessage) { Assert.notNull(arguments, "arguments must not be null"); Assert.notNull(startTime, "startTime must not be null"); @@ -81,6 +90,7 @@ public class TaskExecution { this.arguments = new ArrayList<>(arguments); this.startTime = (Date)startTime.clone(); this.endTime = (endTime != null) ? (Date)endTime.clone() : null; + this.errorMessage = errorMessage; } public long getExecutionId() { @@ -135,6 +145,14 @@ public class TaskExecution { this.arguments = new ArrayList<> (arguments); } + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + @Override public String toString() { return "TaskExecution{" + @@ -144,6 +162,7 @@ public class TaskExecution { ", startTime=" + startTime + ", endTime=" + endTime + ", exitMessage='" + exitMessage + '\'' + + ", errorMessage='" + errorMessage + "\'" + ", arguments=" + arguments + '}'; } diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java index 4755ca13..d929629a 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java @@ -42,6 +42,20 @@ public interface TaskRepository { TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage); + /** + * Notifies the repository that a taskExecution has completed. + * + * @param executionId to the task execution to be updated. + * @param exitCode to be stored for this task. + * @param endTime designated when the task completed. + * @param exitMessage to be stored for the task. + * @return the updated {@link TaskExecution} + * @since 1.1.0 + */ + @Transactional + TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, + String exitMessage, String errorMessage); + /** * Notifies the repository that a taskExecution needs to be created. * diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/JdbcTaskExecutionDao.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/JdbcTaskExecutionDao.java index 70fb190d..0fcabcd8 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/JdbcTaskExecutionDao.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/JdbcTaskExecutionDao.java @@ -58,7 +58,7 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao { public static final String SELECT_CLAUSE = "TASK_EXECUTION_ID, " + "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, " - + "EXIT_MESSAGE, LAST_UPDATED "; + + "EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED "; public static final String FROM_CLAUSE = "%PREFIX%EXECUTION"; @@ -78,12 +78,12 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao { + "%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = ?"; private static final String UPDATE_TASK_EXECUTION = "UPDATE %PREFIX%EXECUTION set " - + "END_TIME = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, LAST_UPDATED = ? " - + "where TASK_EXECUTION_ID = ?"; + + "END_TIME = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, ERROR_MESSAGE = ?, " + + "LAST_UPDATED = ? where TASK_EXECUTION_ID = ?"; private static final String GET_EXECUTION_BY_ID = "SELECT TASK_EXECUTION_ID, " + "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, " - + "EXIT_MESSAGE, LAST_UPDATED " + + "EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED " + "from %PREFIX%EXECUTION where TASK_EXECUTION_ID = ?"; private static final String FIND_ARGUMENT_FROM_ID = "SELECT TASK_EXECUTION_ID, " @@ -129,7 +129,7 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao { Date startTime, List arguments) { long taskExecutionId = getNextExecutionId(); TaskExecution taskExecution = new TaskExecution(taskExecutionId, null, taskName, - startTime, null, null, arguments); + startTime, null, null, arguments, null); Object[] queryParameters = new Object[]{ taskExecutionId, startTime, taskName, new Date()}; jdbcTemplate.update( @@ -142,7 +142,7 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao { @Override public void completeTaskExecution(long taskExecutionId, Integer exitCode, Date endTime, - String exitMessage) { + String exitMessage, String errorMessage) { // Check if given TaskExecution's Id already exists, if none is found // it is invalid and an exception should be thrown. if (jdbcTemplate.queryForObject(getQuery(CHECK_TASK_EXECUTION_EXISTS), Integer.class, @@ -150,15 +150,21 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao { throw new IllegalStateException("Invalid TaskExecution, ID " + taskExecutionId + " not found."); } - Object[] parameters = new Object[]{ endTime, exitCode, exitMessage, new Date(), + Object[] parameters = new Object[]{ endTime, exitCode, exitMessage, errorMessage, new Date(), taskExecutionId}; jdbcTemplate.update( getQuery(UPDATE_TASK_EXECUTION), parameters, - new int[]{ Types.TIMESTAMP, Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP, + new int[]{ Types.TIMESTAMP, Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.BIGINT}); } + @Override + public void completeTaskExecution(long taskExecutionId, Integer exitCode, Date endTime, + String exitMessage) { + completeTaskExecution(taskExecutionId, exitCode, endTime, exitMessage, null); + } + /** * Public setter for the table prefix property. This will be prefixed to all * the table names before queries are executed. Defaults to @@ -374,7 +380,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao { rs.getTimestamp("START_TIME"), rs.getTimestamp("END_TIME"), rs.getString("EXIT_MESSAGE"), - getTaskArguments(id)); + getTaskArguments(id), + rs.getString("ERROR_MESSAGE")); } private Integer getNullableExitCode(ResultSet rs) throws SQLException { diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/MapTaskExecutionDao.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/MapTaskExecutionDao.java index b9405c17..fb9bf276 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/MapTaskExecutionDao.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/MapTaskExecutionDao.java @@ -56,17 +56,23 @@ public class MapTaskExecutionDao implements TaskExecutionDao { Date startTime, List arguments) { long taskExecutionId = getNextExecutionId(); TaskExecution taskExecution = new TaskExecution(taskExecutionId, null, taskName, - startTime, null, null, arguments); + startTime, null, null, arguments, null); taskExecutions.put(taskExecutionId, taskExecution); return taskExecution; } @Override - public void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage) { + public void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage, String errorMessage) { TaskExecution taskExecution= taskExecutions.get(executionId); taskExecution.setEndTime(endTime); taskExecution.setExitCode(exitCode); taskExecution.setExitMessage(exitMessage); + taskExecution.setErrorMessage(errorMessage); + } + + @Override + public void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage) { + completeTaskExecution(executionId, exitCode, endTime, exitMessage, null); } @Override diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/TaskExecutionDao.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/TaskExecutionDao.java index 91f2c1a8..c162040c 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/TaskExecutionDao.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/TaskExecutionDao.java @@ -42,6 +42,18 @@ public interface TaskExecutionDao { TaskExecution createTaskExecution( String taskName, Date startTime, List arguments); + /** + * Update and existing {@link TaskExecution}. + * + * @param executionId the id of the taskExecution to be updated. + * @param exitCode the status of the task upon completion. + * @param endTime the time the task completed. + * @param exitMessage the message assigned to the task upon completion. + * @param errorMessage error information available upon failure of a task. + * @since 1.1.0 + */ + void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage, String errorMessage); + /** * Update and existing {@link TaskExecution}. * diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java index d706a1b4..ee1b6934 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java @@ -51,19 +51,25 @@ public class SimpleTaskRepository implements TaskRepository { this.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean; } + @Override + public TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage) { + return completeTaskExecution(executionId, exitCode, endTime, exitMessage, null); + } + @Override public TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, - String exitMessage) { + String exitMessage, String errorMessage) { initialize(); validateExitInformation(executionId, exitCode, endTime); exitMessage = trimExitMessage(exitMessage); - taskExecutionDao.completeTaskExecution(executionId, exitCode, endTime, exitMessage); + taskExecutionDao.completeTaskExecution(executionId, exitCode, endTime, exitMessage, errorMessage); logger.debug("Updating: TaskExecution with executionId="+executionId + " with the following {" + "exitCode=" + exitCode + ", endTime=" + endTime + ", exitMessage='" + exitMessage + '\'' + + ", errorMessage='" + errorMessage + '\'' + '}'); return taskExecutionDao.getTaskExecution(executionId); diff --git a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-h2.sql b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-h2.sql index 06cc6fb0..de1c01d1 100644 --- a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-h2.sql +++ b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-h2.sql @@ -6,6 +6,7 @@ CREATE TABLE TASK_EXECUTION ( TASK_NAME VARCHAR(100) , EXIT_CODE INTEGER , EXIT_MESSAGE VARCHAR(2500) , + ERROR_MESSAGE VARCHAR(2500) , LAST_UPDATED TIMESTAMP ); diff --git a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-hsqldb.sql b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-hsqldb.sql index 76eba155..50a91ae8 100644 --- a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-hsqldb.sql +++ b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-hsqldb.sql @@ -6,6 +6,7 @@ CREATE TABLE TASK_EXECUTION ( TASK_NAME VARCHAR(100) , EXIT_CODE INTEGER , EXIT_MESSAGE VARCHAR(2500) , + ERROR_MESSAGE VARCHAR(2500) , LAST_UPDATED TIMESTAMP ); diff --git a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-mysql.sql b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-mysql.sql index 80e13af4..4f056b88 100644 --- a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-mysql.sql +++ b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-mysql.sql @@ -6,6 +6,7 @@ CREATE TABLE TASK_EXECUTION ( TASK_NAME VARCHAR(100) , EXIT_CODE INTEGER , EXIT_MESSAGE VARCHAR(2500) , + ERROR_MESSAGE VARCHAR(2500) , LAST_UPDATED TIMESTAMP ) ENGINE=InnoDB; diff --git a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-oracle10g.sql b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-oracle10g.sql index f98cfa57..0a188dcc 100644 --- a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-oracle10g.sql +++ b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-oracle10g.sql @@ -6,6 +6,7 @@ CREATE TABLE TASK_EXECUTION ( TASK_NAME VARCHAR2(100) , EXIT_CODE INTEGER , EXIT_MESSAGE VARCHAR2(2500) , + ERROR_MESSAGE VARCHAR2(2500) , LAST_UPDATED TIMESTAMP ); diff --git a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-postgresql.sql b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-postgresql.sql index f7ae44e7..89456f6b 100644 --- a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-postgresql.sql +++ b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-postgresql.sql @@ -6,6 +6,7 @@ CREATE TABLE TASK_EXECUTION ( TASK_NAME VARCHAR(100) , EXIT_CODE INTEGER , EXIT_MESSAGE VARCHAR(2500) , + ERROR_MESSAGE VARCHAR(2500) , LAST_UPDATED TIMESTAMP ); diff --git a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-sqlserver.sql b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-sqlserver.sql index 7378b5ba..3f84313c 100644 --- a/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-sqlserver.sql +++ b/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-sqlserver.sql @@ -5,6 +5,7 @@ CREATE TABLE TASK_EXECUTION ( TASK_NAME VARCHAR(100) , EXIT_CODE INTEGER , EXIT_MESSAGE VARCHAR(2500) , + ERROR_MESSAGE VARCHAR(2500) , LAST_UPDATED DATETIME ); diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java index b1bf141e..1e5e3f60 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java @@ -28,8 +28,8 @@ public class TaskCoreTests { private static final String UPDATE_TASK_MESSAGE = "Updating: TaskExecution with executionId="; private static final String SUCCESS_EXIT_CODE_MESSAGE = "with the following {exitCode=0"; private static final String EXCEPTION_EXIT_CODE_MESSAGE = "with the following {exitCode=1"; - private static final String EXIT_MESSAGE = - "exitMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner"; + private static final String ERROR_MESSAGE = + "errorMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner"; private ConfigurableApplicationContext applicationContext; @@ -83,7 +83,7 @@ public class TaskCoreTests { assertTrue("Test results have incorrect exit code: " + output, output.contains(EXCEPTION_EXIT_CODE_MESSAGE)); assertTrue("Test results have incorrect exit message: " + output, - output.contains(EXIT_MESSAGE)); + output.contains(ERROR_MESSAGE)); assertTrue("Test results have exception message: " + output, output.contains(EXCEPTION_MESSAGE)); } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java index 3ea1f7b0..05ad76de 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java @@ -71,7 +71,7 @@ public class TaskExecutionListenerTests { DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = context.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class); TaskExecution taskExecution = new TaskExecution(0, null, "wombat", - new Date(), new Date(), null, new ArrayList()); + new Date(), new Date(), null, new ArrayList(), null); verifyListenerResults(true, false, false, taskExecution,taskExecutionListener); } @@ -87,7 +87,7 @@ public class TaskExecutionListenerTests { context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context)); TaskExecution taskExecution = new TaskExecution(0, 0, "wombat", - new Date(), new Date(), null, new ArrayList()); + new Date(), new Date(), null, new ArrayList(), null); verifyListenerResults(true, true, false, taskExecution,taskExecutionListener); } @@ -106,7 +106,7 @@ public class TaskExecutionListenerTests { context.publishEvent(new ApplicationReadyEvent(application, new String[0], context)); TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(), - new Date(), null, new ArrayList()); + new Date(), null, new ArrayList(), null); verifyListenerResults(true, true, true, taskExecution,taskExecutionListener); } @@ -120,7 +120,7 @@ public class TaskExecutionListenerTests { DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = context.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class); TaskExecution taskExecution = new TaskExecution(0, null, "wombat", - new Date(), new Date(), null, new ArrayList()); + new Date(), new Date(), null, new ArrayList(), null); verifyListenerResults(true, false, false, taskExecution,annotatedListener); } @@ -136,7 +136,7 @@ public class TaskExecutionListenerTests { context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context)); TaskExecution taskExecution = new TaskExecution(0, 0, "wombat", - new Date(), new Date(), null, new ArrayList()); + new Date(), new Date(), null, new ArrayList(), null); verifyListenerResults(true, true, false, taskExecution,annotatedListener); } @@ -155,7 +155,7 @@ public class TaskExecutionListenerTests { context.publishEvent(new ApplicationReadyEvent(application, new String[0], context)); TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(), - new Date(), null, new ArrayList()); + new Date(), null, new ArrayList(), null); verifyListenerResults(true, true, true, taskExecution,annotatedListener); } @@ -169,13 +169,16 @@ public class TaskExecutionListenerTests { assertEquals(TestListener.END_MESSAGE, actualListener.getTaskExecution().getExitMessage()); assertNotNull(actualListener.getThrowable()); assertTrue(actualListener.getThrowable() instanceof RuntimeException); + assertTrue(actualListener.getTaskExecution().getErrorMessage().startsWith("java.lang.RuntimeException: This was expected")); } else if(isTaskEnd){ assertEquals(TestListener.END_MESSAGE, actualListener.getTaskExecution().getExitMessage()); + assertNull(actualListener.getTaskExecution().getErrorMessage()); assertNull(actualListener.getThrowable()); } else { assertEquals(TestListener.START_MESSAGE, actualListener.getTaskExecution().getExitMessage()); + assertNull(actualListener.getTaskExecution().getErrorMessage()); assertNull(actualListener.getThrowable()); } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java index 4e2b3341..ed9f4c87 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java @@ -139,7 +139,7 @@ public class TaskLifecycleListenerTests { assertEquals(exitCode, taskExecution.getExitCode()); if(exception != null) { - assertTrue(taskExecution.getExitMessage().length() > exception.getStackTrace().length); + assertTrue(taskExecution.getErrorMessage().length() > exception.getStackTrace().length); } else { assertNull(taskExecution.getExitMessage()); diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java index d5326b4c..4efe43e0 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java @@ -16,18 +16,19 @@ package org.springframework.cloud.task.repository.database.support; -import static org.junit.Assert.assertEquals; - import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + import org.springframework.cloud.task.util.TestDBUtils; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import static org.junit.Assert.assertEquals; + /** * @author Glenn Renfro */ @@ -42,30 +43,30 @@ public class FindAllPagingQueryProviderTests { public static Collection data() { return Arrays.asList(new Object[][]{ {"Oracle", "SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED FROM " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED FROM " + "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED, ROWNUM as " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, ROWNUM as " + "TMP_ROW_NUM FROM (SELECT TASK_EXECUTION_ID, START_TIME, " - + "END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED " + + "END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED " + "FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, " + "TASK_EXECUTION_ID DESC)) WHERE TMP_ROW_NUM >= 1 AND " + "TMP_ROW_NUM < 11"}, {"HSQL Database Engine","SELECT LIMIT 0 10 TASK_EXECUTION_ID, " + "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, " - + "LAST_UPDATED FROM %PREFIX%EXECUTION ORDER BY " + + "ERROR_MESSAGE, LAST_UPDATED FROM %PREFIX%EXECUTION ORDER BY " + "START_TIME DESC, TASK_EXECUTION_ID DESC"}, {"PostgreSQL","SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, " - + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED " + + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED " + "FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, " + "TASK_EXECUTION_ID DESC LIMIT 10 OFFSET 0"}, {"MySQL","SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED FROM " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED FROM " + "%PREFIX%EXECUTION ORDER BY START_TIME DESC, " + "TASK_EXECUTION_ID DESC LIMIT 0, 10"}, {"Microsoft SQL Server","SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, " - + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED FROM " + + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED FROM " + "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED, ROW_NUMBER() " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, ROW_NUMBER() " + "OVER (ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC) AS " + "TMP_ROW_NUM FROM %PREFIX%EXECUTION) TASK_EXECUTION_PAGE " + "WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11 ORDER BY START_TIME DESC, " diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/WhereClausePagingQueryProviderTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/WhereClausePagingQueryProviderTests.java index e3cb8f34..2e67fc68 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/WhereClausePagingQueryProviderTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/WhereClausePagingQueryProviderTests.java @@ -16,19 +16,20 @@ package org.springframework.cloud.task.repository.database.support; -import static org.junit.Assert.assertEquals; - import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + import org.springframework.cloud.task.repository.database.PagingQueryProvider; import org.springframework.cloud.task.util.TestDBUtils; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import static org.junit.Assert.assertEquals; + /** * @author Glenn Renfro */ @@ -43,34 +44,34 @@ public class WhereClausePagingQueryProviderTests { public static Collection data() { return Arrays.asList(new Object[][]{ {"Oracle", "SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED FROM " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED FROM " + "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED, ROWNUM as " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, ROWNUM as " + "TMP_ROW_NUM FROM (SELECT TASK_EXECUTION_ID, START_TIME, " - + "END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED " - + "FROM %PREFIX%EXECUTION " + + "END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, " + + "LAST_UPDATED FROM %PREFIX%EXECUTION " + "WHERE TASK_EXECUTION_ID = '0000' ORDER BY START_TIME DESC, " + "TASK_EXECUTION_ID DESC)) WHERE TMP_ROW_NUM >= 1 AND " + "TMP_ROW_NUM < 11"}, {"HSQL Database Engine","SELECT LIMIT 0 10 TASK_EXECUTION_ID, " + "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, " - + "LAST_UPDATED FROM %PREFIX%EXECUTION " + + "ERROR_MESSAGE, LAST_UPDATED FROM %PREFIX%EXECUTION " + "WHERE TASK_EXECUTION_ID = '0000' ORDER BY " + "START_TIME DESC, TASK_EXECUTION_ID DESC"}, {"PostgreSQL","SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, " - + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED " + + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED " + "FROM %PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = '0000' " + "ORDER BY START_TIME DESC, " + "TASK_EXECUTION_ID DESC LIMIT 10 OFFSET 0"}, {"MySQL","SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED FROM " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED FROM " + "%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = '0000' " + "ORDER BY START_TIME DESC, " + "TASK_EXECUTION_ID DESC LIMIT 0, 10"}, {"Microsoft SQL Server","SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, " - + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED FROM " + + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED FROM " + "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, " - + "EXIT_CODE, EXIT_MESSAGE, LAST_UPDATED, ROW_NUMBER() " + + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, ROW_NUMBER() " + "OVER (ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC) AS " + "TMP_ROW_NUM FROM %PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = " + "'0000') TASK_EXECUTION_PAGE WHERE TMP_ROW_NUM >= 1 " diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskExecutionCreator.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskExecutionCreator.java index 3e42e027..3344ee5b 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskExecutionCreator.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskExecutionCreator.java @@ -70,6 +70,6 @@ public class TaskExecutionCreator { TaskExecution expectedTaskExecution) { return taskRepository.completeTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getExitCode(), expectedTaskExecution.getEndTime(), - expectedTaskExecution.getExitMessage()); + expectedTaskExecution.getExitMessage(), expectedTaskExecution.getErrorMessage()); } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDBUtils.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDBUtils.java index 694dfab6..a79dc672 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDBUtils.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDBUtils.java @@ -73,7 +73,8 @@ public class TestDBUtils { rs.getTimestamp("START_TIME"), rs.getTimestamp("END_TIME"), rs.getString("EXIT_MESSAGE"), - new ArrayList(0)); + new ArrayList(0), + rs.getString("ERROR_MESSAGE")); return taskExecution; } }); diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestVerifierUtils.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestVerifierUtils.java index e3438394..df00a6b5 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestVerifierUtils.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestVerifierUtils.java @@ -90,7 +90,7 @@ public class TestVerifierUtils { String taskName = UUID.randomUUID().toString(); return new TaskExecution(executionId, 0, taskName, - startTime, null, null, new ArrayList()); + startTime, null, null, new ArrayList(), null); } /** @@ -108,7 +108,7 @@ public class TestVerifierUtils { String exitMessage = UUID.randomUUID().toString(); return new TaskExecution(executionId, exitCode, taskName, - startTime, endTime, exitMessage, new ArrayList()); + startTime, endTime, exitMessage, new ArrayList(), null); } /** @@ -117,7 +117,6 @@ public class TestVerifierUtils { * @return */ public static TaskExecution createSampleTaskExecution(long executionId) { - Random randomGenerator = new Random(); Date startTime = new Date(); String taskName = UUID.randomUUID().toString(); List args = new ArrayList<>(ARG_SIZE); @@ -125,7 +124,7 @@ public class TestVerifierUtils { args.add(UUID.randomUUID().toString()); } return new TaskExecution(executionId, null, taskName, - startTime, null, null, args); + startTime, null, null, args, null); } /** @@ -153,6 +152,9 @@ public class TestVerifierUtils { assertEquals("exitMessage must be equal", expectedTaskExecution.getExitMessage(), actualTaskExecution.getExitMessage()); + assertEquals("errorMessage must be equal", + expectedTaskExecution.getErrorMessage(), + actualTaskExecution.getErrorMessage()); if (expectedTaskExecution.getArguments() != null) { assertNotNull("arguments should not be null", actualTaskExecution.getArguments()); diff --git a/spring-cloud-task-docs/src/main/asciidoc/features.adoc b/spring-cloud-task-docs/src/main/asciidoc/features.adoc index 40ddb2fd..555d3aa2 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/features.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/features.adoc @@ -79,9 +79,12 @@ assumed to be 0. |The time the task was completed as indicated by the `ApplicationReadyEvent`. |`exitMessage` -|Any information available at the time of exit. If an exception is the cause of the end -of the task (as indicated via an `ApplicationFailedEvent`), the stack trace for that -exception will be stored here. +|Any information available at the time of exit. This can programatically be set via a +`TaskExecutionListener`. + +|`errorMessage` +|If an exception is the cause of the end of the task (as indicated via an +`ApplicationFailedEvent`), the stack trace for that exception will be stored here. |`arguments` |A `List` of the string command line arguments as they were passed into the executable boot diff --git a/spring-cloud-task-integration-tests/pom.xml b/spring-cloud-task-integration-tests/pom.xml index 32199a6b..6803b1b5 100644 --- a/spring-cloud-task-integration-tests/pom.xml +++ b/spring-cloud-task-integration-tests/pom.xml @@ -107,7 +107,7 @@ - skipIntegrationTests + integrationTests @@ -115,7 +115,25 @@ maven-surefire-plugin 2.12.4 - true + false + + + + + + + skipIntegrationTests + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + false diff --git a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java index 51c2acd7..4913a54b 100644 --- a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java +++ b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java @@ -44,10 +44,13 @@ import org.springframework.cloud.task.repository.support.SimpleTaskExplorer; import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jdbc.datasource.init.DataSourceInitializer; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.messaging.support.GenericMessage; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.SocketUtils; @@ -61,8 +64,8 @@ public class TaskLauncherSinkTests { private final static int WAIT_INTERVAL = 500; private final static int MAX_WAIT_TIME = 5000; - private final static String URL = "maven://org.springframework.cloud.task.app:" - + "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT"; + private final static String URL = "maven://io.spring.cloud:" + + "timestamp-task:jar:1.1.0.BUILD-SNAPSHOT"; private final static String DATASOURCE_URL; private final static String DATASOURCE_USER_NAME = "SA"; private final static String DATASOURCE_USER_PASSWORD = ""; @@ -104,6 +107,7 @@ public class TaskLauncherSinkTests { properties.put("spring.datasource.password", DATASOURCE_USER_PASSWORD); properties.put("spring.datasource.driverClassName", DATASOURCE_DRIVER_CLASS_NAME); properties.put("spring.application.name",TASK_NAME); + properties.put("spring.cloud.task.initialize.enable", "false"); JdbcTemplate template = new JdbcTemplate(this.dataSource); template.execute("DROP TABLE IF EXISTS TASK_TASK_BATCH"); @@ -119,6 +123,16 @@ public class TaskLauncherSinkTests { template.execute("DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_CONTEXT"); template.execute("DROP TABLE IF EXISTS BATCH_JOB_EXECUTION"); template.execute("DROP TABLE IF EXISTS BATCH_JOB_INSTANCE"); + + + DataSourceInitializer initializer = new DataSourceInitializer(); + + initializer.setDataSource(dataSource); + ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); + databasePopulator.addScript(new ClassPathResource("/org/springframework/cloud/task/schema-h2.sql")); + initializer.setDatabasePopulator(databasePopulator); + + initializer.afterPropertiesSet(); } @Test diff --git a/spring-cloud-task-samples/partitioned-batch-job/pom.xml b/spring-cloud-task-samples/partitioned-batch-job/pom.xml index 742a6ddc..c42aebcc 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/pom.xml +++ b/spring-cloud-task-samples/partitioned-batch-job/pom.xml @@ -115,6 +115,45 @@ - + + + + integrationTests + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + + **/TaskPartitionerTests.java + + + + + + + + skipIntegrationTests + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + + **/TaskPartitionerTests.java + + + + + + + diff --git a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java index e3fcddff..cc99955b 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java +++ b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java @@ -99,7 +99,7 @@ public class JobConfiguration { @Bean public PartitionHandler partitionHandler(TaskLauncher taskLauncher, JobExplorer jobExplorer) throws Exception { - Resource resource = resourceLoader.getResource("maven://io.spring.cloud:partitioned-batch-job:1.0.3.BUILD-SNAPSHOT"); + Resource resource = resourceLoader.getResource("maven://io.spring.cloud:partitioned-batch-job:1.1.0.BUILD-SNAPSHOT"); DeployerPartitionHandler partitionHandler = new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, "workerStep"); diff --git a/spring-cloud-task-samples/timestamp/pom.xml b/spring-cloud-task-samples/timestamp/pom.xml index 4ac76257..96096520 100644 --- a/spring-cloud-task-samples/timestamp/pom.xml +++ b/spring-cloud-task-samples/timestamp/pom.xml @@ -52,6 +52,14 @@ spring-boot-configuration-processor true + + org.springframework.boot + spring-boot-starter-jdbc + + + com.h2database + h2 +