SCT-35 Tasks Support TaskExecutionListener
resolves spring-cloud/spring-cloud-task#35 TaskExecutionListener now supports TaskExecution Params
This commit is contained in:
committed by
Michael Minella
parent
91fa6be092
commit
20a56c9581
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.listener;
|
||||
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.cloud.task.repository.TaskRepository;
|
||||
|
||||
/**
|
||||
* The listener interface for receiving task execution events.
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public interface TaskExecutionListener {
|
||||
|
||||
/**
|
||||
* Invoked after the {@link TaskExecution} has been stored in the {@link TaskRepository}.
|
||||
* @param taskExecution instance containing the information about the current task.
|
||||
*/
|
||||
public void onTaskStartup(TaskExecution taskExecution);
|
||||
|
||||
/**
|
||||
* Invoked before the {@link TaskExecution} has been updated in the {@link TaskRepository}
|
||||
* upon task end.
|
||||
* @param taskExecution instance containing the information about the current task.
|
||||
*/
|
||||
public void onTaskEnd(TaskExecution taskExecution);
|
||||
|
||||
/**
|
||||
* Invoked if an uncaught exception occurs during a task execution. This invocation
|
||||
* will occur before the {@link TaskExecution} has been updated in the {@link TaskRepository}
|
||||
* and before the onTaskEnd is called.
|
||||
* @param taskExecution instance containing the information about the current task.
|
||||
* @param throwable the uncaught exception that was thrown during task execution.
|
||||
*/
|
||||
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable);
|
||||
|
||||
}
|
||||
@@ -19,12 +19,14 @@ import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ExitCodeEvent;
|
||||
import org.springframework.boot.context.event.ApplicationFailedEvent;
|
||||
@@ -57,6 +59,9 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class TaskLifecycleListener implements ApplicationListener<ApplicationEvent>{
|
||||
|
||||
@Autowired(required = false)
|
||||
Collection<TaskExecutionListener> taskExecutionListeners;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(TaskLifecycleListener.class);
|
||||
|
||||
private final TaskRepository taskRepository;
|
||||
@@ -142,6 +147,11 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
|
||||
this.taskExecution.setExitMessage(stackTraceToString(this.applicationFailedEvent.getException()));
|
||||
}
|
||||
|
||||
if(this.taskExecution.getExitCode() != 0){
|
||||
taskExecution.setExitMessage(invokeOnTaskError(taskExecution,
|
||||
this.applicationFailedEvent.getException()).getExitMessage());
|
||||
}
|
||||
taskExecution.setExitMessage(invokeOnTaskEnd(taskExecution).getExitMessage());
|
||||
taskRepository.update(taskExecution);
|
||||
}
|
||||
else {
|
||||
@@ -169,5 +179,47 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
|
||||
logger.error("Multiple start events have been received. The first one was " +
|
||||
"recorded.");
|
||||
}
|
||||
taskExecution.setExitMessage(invokeOnTaskStartup(taskExecution).getExitMessage());
|
||||
}
|
||||
|
||||
private TaskExecution invokeOnTaskStartup(TaskExecution taskExecution){
|
||||
TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);
|
||||
if (taskExecutionListeners != null) {
|
||||
for (TaskExecutionListener taskExecutionListener : taskExecutionListeners) {
|
||||
taskExecutionListener.onTaskStartup(listenerTaskExecution);
|
||||
}
|
||||
}
|
||||
return listenerTaskExecution;
|
||||
}
|
||||
|
||||
private TaskExecution invokeOnTaskEnd(TaskExecution taskExecution){
|
||||
TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);
|
||||
if (taskExecutionListeners != null) {
|
||||
for (TaskExecutionListener taskExecutionListener : taskExecutionListeners) {
|
||||
taskExecutionListener.onTaskEnd(listenerTaskExecution);
|
||||
}
|
||||
}
|
||||
return listenerTaskExecution;
|
||||
}
|
||||
|
||||
private TaskExecution invokeOnTaskError(TaskExecution taskExecution, Throwable throwable){
|
||||
TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);
|
||||
if (taskExecutionListeners != null) {
|
||||
for (TaskExecutionListener taskExecutionListener : taskExecutionListeners) {
|
||||
taskExecutionListener.onTaskFailed(listenerTaskExecution, throwable);
|
||||
}
|
||||
}
|
||||
return listenerTaskExecution;
|
||||
}
|
||||
|
||||
private TaskExecution getTaskExecutionCopy(TaskExecution taskExecution){
|
||||
Date startTime = new Date(taskExecution.getStartTime().getTime());
|
||||
Date endTime = (taskExecution.getEndTime() == null) ?
|
||||
null : new Date(taskExecution.getEndTime().getTime());
|
||||
|
||||
return new TaskExecution(taskExecution.getExecutionId(),
|
||||
taskExecution.getExitCode(), taskExecution.getTaskName(), startTime,
|
||||
endTime,taskExecution.getExitMessage(),
|
||||
Collections.unmodifiableList(taskExecution.getParameters()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.listener;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.cloud.task.util.TestDefaultConfiguration;
|
||||
import org.springframework.cloud.task.util.TestDefaultListenerConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
|
||||
/**
|
||||
* Verifies that the TaskExecutionListener invocations occur at the appropriate task
|
||||
* lifecycle stages.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class TaskExecutionListenerTests {
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
private static final String EXCEPTION_MESSAGE = "This was expected";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = new AnnotationConfigApplicationContext();
|
||||
context.setId("testTask");
|
||||
context.register(TestDefaultListenerConfiguration.class,
|
||||
TestDefaultConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskCreate() {
|
||||
context.refresh();
|
||||
TestDefaultListenerConfiguration.TestTaskExecutionListener taskExecutionListener =
|
||||
context.getBean(TestDefaultListenerConfiguration.TestTaskExecutionListener.class);
|
||||
TaskExecution taskExecution = new TaskExecution(0, null, "wombat",
|
||||
new Date(), new Date(), null, new ArrayList<String>());
|
||||
verifyListenerResults(true, false, false, taskExecution,taskExecutionListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskUpdate() {
|
||||
context.refresh();
|
||||
TestDefaultListenerConfiguration.TestTaskExecutionListener taskExecutionListener =
|
||||
context.getBean(TestDefaultListenerConfiguration.TestTaskExecutionListener.class);
|
||||
context.publishEvent(new ContextClosedEvent(context));
|
||||
|
||||
TaskExecution taskExecution = new TaskExecution(0, 0, "wombat",
|
||||
new Date(), new Date(), null, new ArrayList<String>());
|
||||
verifyListenerResults(true, true, false, taskExecution,taskExecutionListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskFail() {
|
||||
RuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE);
|
||||
context.refresh();
|
||||
context.publishEvent(new ApplicationFailedEvent(new SpringApplication(), new String[0], context, exception));
|
||||
context.publishEvent(new ContextClosedEvent(context));
|
||||
TestDefaultListenerConfiguration.TestTaskExecutionListener taskExecutionListener =
|
||||
context.getBean(TestDefaultListenerConfiguration.TestTaskExecutionListener.class);
|
||||
|
||||
TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(),
|
||||
new Date(), null, new ArrayList<String>());
|
||||
verifyListenerResults(true, true, true, taskExecution,taskExecutionListener);
|
||||
}
|
||||
|
||||
private void verifyListenerResults (boolean isTaskStartup, boolean isTaskEnd,
|
||||
boolean isTaskFailed, TaskExecution taskExecution,
|
||||
TestDefaultListenerConfiguration.TestTaskExecutionListener actualListener){
|
||||
assertEquals(isTaskStartup,actualListener.isTaskStartup());
|
||||
assertEquals(isTaskEnd,actualListener.isTaskEnd());
|
||||
assertEquals(isTaskFailed,actualListener.isTaskFailed());
|
||||
if(isTaskFailed){
|
||||
assertEquals(TestDefaultListenerConfiguration.TestTaskExecutionListener.END_MESSAGE, actualListener.getTaskExecution().getExitMessage());
|
||||
assertNotNull(actualListener.getThrowable());
|
||||
assertTrue(actualListener.getThrowable() instanceof RuntimeException);
|
||||
}
|
||||
else if(isTaskEnd){
|
||||
assertEquals(TestDefaultListenerConfiguration.TestTaskExecutionListener.END_MESSAGE, actualListener.getTaskExecution().getExitMessage());
|
||||
assertNull(actualListener.getThrowable());
|
||||
}
|
||||
else {
|
||||
assertEquals(TestDefaultListenerConfiguration.TestTaskExecutionListener.START_MESSAGE, actualListener.getTaskExecution().getExitMessage());
|
||||
assertNull(actualListener.getThrowable());
|
||||
}
|
||||
|
||||
assertEquals(taskExecution.getExecutionId(), actualListener.getTaskExecution().getExecutionId());
|
||||
assertEquals(taskExecution.getExitCode(), actualListener.getTaskExecution().getExitCode());
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import java.util.Set;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.util;
|
||||
|
||||
import org.springframework.cloud.task.listener.TaskExecutionListener;
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Initializes the beans needed to TestExecutionListenerTests.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
@Configuration
|
||||
public class TestDefaultListenerConfiguration {
|
||||
|
||||
@Bean
|
||||
public TestTaskExecutionListener taskExecutionListener() {
|
||||
return new TestTaskExecutionListener();
|
||||
}
|
||||
|
||||
|
||||
public class TestTaskExecutionListener implements TaskExecutionListener {
|
||||
|
||||
public static final String START_MESSAGE = "FOO";
|
||||
public static final String ERROR_MESSAGE = "BAR";
|
||||
public static final String END_MESSAGE = "BAZ";
|
||||
|
||||
private boolean isTaskStartup;
|
||||
private boolean isTaskEnd;
|
||||
private boolean isTaskFailed;
|
||||
private TaskExecution taskExecution;
|
||||
private Throwable throwable;
|
||||
|
||||
@Override
|
||||
public void onTaskStartup(TaskExecution taskExecution) {
|
||||
isTaskStartup = true;
|
||||
this.taskExecution = taskExecution;
|
||||
this.taskExecution.setExitMessage(START_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskEnd(TaskExecution taskExecution) {
|
||||
isTaskEnd = true;
|
||||
this.taskExecution = taskExecution;
|
||||
this.taskExecution.setExitMessage(END_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
|
||||
isTaskFailed = true;
|
||||
this.taskExecution = taskExecution;
|
||||
this.throwable = throwable;
|
||||
this.taskExecution.setExitMessage(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
public boolean isTaskStartup() {
|
||||
return isTaskStartup;
|
||||
}
|
||||
|
||||
public boolean isTaskEnd() {
|
||||
return isTaskEnd;
|
||||
}
|
||||
|
||||
public boolean isTaskFailed() {
|
||||
return isTaskFailed;
|
||||
}
|
||||
|
||||
public TaskExecution getTaskExecution() {
|
||||
return this.taskExecution;
|
||||
}
|
||||
|
||||
public Throwable getThrowable(){
|
||||
return throwable;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user