Prevent a task from starting if an inst with the same name is running.

resolves #81

Using LockRegistryLeaderInitiator to do leadership election.

When task is started and singleInstanceEnabled isset to true then we use leader election
to determine if a task needs to be started.

Error Event Name had to be updated
This commit is contained in:
Glenn Renfro
2017-09-27 17:39:29 -04:00
committed by Michael Minella
parent 94e074d841
commit d8a73ba183
19 changed files with 628 additions and 5 deletions

View File

@@ -19,9 +19,12 @@ package org.springframework.cloud.task.executionid;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.sql.DataSource;
import org.h2.tools.Server;
@@ -51,6 +54,7 @@ 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.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
@@ -122,6 +126,7 @@ public class TaskStartTests {
template.execute("DROP TABLE IF EXISTS TASK_SEQ");
template.execute("DROP TABLE IF EXISTS TASK_EXECUTION_PARAMS");
template.execute("DROP TABLE IF EXISTS TASK_EXECUTION");
template.execute("DROP TABLE IF EXISTS TASK_LOCK");
template.execute("DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_SEQ");
template.execute("DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT");
template.execute("DROP TABLE IF EXISTS BATCH_STEP_EXECUTION");
@@ -184,6 +189,43 @@ public class TaskStartTests {
taskRepository.completeTaskExecution(1, 0, new Date(),"");
this.applicationContext = getTaskApplication(1).run(new String[0]);
}
@Test
public void testDuplicateTaskExecutionWithSingleInstanceEnabled() throws Exception {
String params[] = {"--spring.cloud.task.singleInstanceEnabled=true",
"--spring.cloud.task.name=foo"};
boolean testFailed = false;
try {
taskRepository.createTaskExecution();
assertEquals("Only one row is expected", 1, taskExplorer.getTaskExecutionCount());
enableLock("foo");
getTaskApplication(1).run(params);
}
catch (ApplicationContextException taskException) {
assertEquals("Failed to start bean 'taskLifecycleListener'; nested " +
"exception is org.springframework.cloud.task." +
"listener.TaskExecutionException: Failed to process " +
"@BeforeTask or @AfterTask annotation because: Task with name \"foo\" is already running.",
taskException.getMessage());
testFailed = true;
}
assertTrue("Expected TaskExecutionException for because of " +
"singleInstanceEnabled is enabled", testFailed);
}
@Test
public void testDuplicateTaskExecutionWithSingleInstanceDisabled() throws Exception {
taskRepository.createTaskExecution();
TaskExecution execution = taskRepository.createTaskExecution();
taskRepository.startTaskExecution(execution.getExecutionId(), "bar",
new Date(), new ArrayList<>(), "");
String params[] = {"--spring.cloud.task.name=bar"};
enableLock("bar");
this.applicationContext = getTaskApplication(1).run(params);
assertTrue(waitForDBToBePopulated());
}
private SpringApplication getTaskApplication(Integer executionId) {
SpringApplication myapp = new SpringApplication(TaskStartApplication.class);
Map<String,Object> myMap = new HashMap<>();
@@ -217,6 +259,16 @@ public class TaskStartTests {
return isDbPopulated;
}
private void enableLock(String lockKey) {
SimpleJdbcInsert taskLockInsert = new SimpleJdbcInsert(this.dataSource).withTableName("TASK_LOCK");
Map<String, Object> taskLockParams = new HashMap<>();
taskLockParams.put("LOCK_KEY", UUID.nameUUIDFromBytes(lockKey.getBytes()).toString());
taskLockParams.put("REGION", "DEFAULT");
taskLockParams.put("CLIENT_ID", "aClientID");
taskLockParams.put("CREATED_DATE", new Date());
taskLockInsert.execute(taskLockParams);
}
@Configuration
public static class TaskLauncherConfiguration {
private static Server defaultServer;