Better support for parallel regions
- Generally fixes #68 - First attempt to externalize event execution from state machine into its own class backed by an interface. This relates to #7 - Change of various places to have better support if execution is done in threads. - Not yet a central place where concurrency can be defines, thus currently rely on global taskExecutor bean when can be overridded from a default which is SyncTaskExecutor. Futher work for that in separate tickets. - Change tasks sample to use a thread pool. - Change of concept how initial state/transition is handled, no longer handled manually in lifecycle method, thus giving a change for initial transition to execute its actions in a multiple threads.
This commit is contained in:
@@ -8,6 +8,8 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.shell.Bootstrap;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
@@ -127,8 +129,7 @@ public class Application {
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
Map<Object, Object> variables = context.getExtendedState().getVariables();
|
||||
if (variables.get("T1").equals(false)) {
|
||||
variables.put("T1", true);
|
||||
if (variables.get("T1").equals(true)) {
|
||||
context.getStateMachine().sendEvent(Events.CONTINUE);
|
||||
} else {
|
||||
context.getStateMachine().sendEvent(Events.FALLBACK);
|
||||
@@ -157,6 +158,13 @@ public class Application {
|
||||
return new Tasks();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
|
||||
taskExecutor.setCorePoolSize(5);
|
||||
return taskExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
//end::snippetA[]
|
||||
|
||||
|
||||
@@ -54,19 +54,25 @@ public class Tasks {
|
||||
@StatesOnTransition(target = States.T1)
|
||||
public void taskT1(ExtendedState extendedState) {
|
||||
log.info("run task on T1");
|
||||
sleep(2000);
|
||||
extendedState.getVariables().put("T1", tasks.get("T1"));
|
||||
log.info("run task on T1 done");
|
||||
}
|
||||
|
||||
@StatesOnTransition(target = States.T2)
|
||||
public void taskT2(ExtendedState extendedState) {
|
||||
log.info("run task on T2");
|
||||
sleep(2000);
|
||||
extendedState.getVariables().put("T2", tasks.get("T2"));
|
||||
log.info("run task on T2 done");
|
||||
}
|
||||
|
||||
@StatesOnTransition(target = States.T3)
|
||||
public void taskT3(ExtendedState extendedState) {
|
||||
log.info("run task on T3");
|
||||
sleep(2000);
|
||||
extendedState.getVariables().put("T3", tasks.get("T3"));
|
||||
log.info("run task on T3 done");
|
||||
}
|
||||
|
||||
@StatesOnTransition(target = States.AUTOMATIC)
|
||||
@@ -87,6 +93,13 @@ public class Tasks {
|
||||
}
|
||||
}
|
||||
|
||||
private static void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tasks " + tasks;
|
||||
|
||||
@@ -46,22 +46,22 @@ public class TasksTests {
|
||||
|
||||
@Test
|
||||
public void testRunOnce() throws InterruptedException {
|
||||
listener.reset(3, 0, 0);
|
||||
listener.reset(9, 0, 0);
|
||||
tasks.run();
|
||||
assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(listener.stateChangedLatch.await(6, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), contains(States.READY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunTwice() throws InterruptedException {
|
||||
listener.reset(3, 0, 0);
|
||||
listener.reset(9, 0, 0);
|
||||
tasks.run();
|
||||
assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(listener.stateChangedLatch.await(6, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), contains(States.READY));
|
||||
|
||||
listener.reset(3, 0, 0);
|
||||
listener.reset(9, 0, 0);
|
||||
tasks.run();
|
||||
assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(listener.stateChangedLatch.await(6, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), contains(States.READY));
|
||||
}
|
||||
|
||||
@@ -70,19 +70,19 @@ public class TasksTests {
|
||||
listener.reset(11, 0, 0);
|
||||
tasks.fail("T1");
|
||||
tasks.run();
|
||||
assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(listener.stateChangedLatch.await(6, TimeUnit.SECONDS), is(true));
|
||||
assertThat(listener.stateChangedCount, is(11));
|
||||
assertThat(machine.getState().getIds(), contains(States.READY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailManualFix() throws InterruptedException {
|
||||
listener.reset(3, 0, 0);
|
||||
listener.reset(9, 0, 0);
|
||||
tasks.fail("T2");
|
||||
tasks.run();
|
||||
tasks.fix("T2");
|
||||
tasks.cont();
|
||||
assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(listener.stateChangedLatch.await(6, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), contains(States.READY));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user