Clear event defer list

- In ReactiveStateMachineExecutor deferList is clear
  with deferred event if it triggers.
- Fixes #747
This commit is contained in:
Janne Valkealahti
2019-05-08 18:27:27 +01:00
parent 95554be3fb
commit 10f0ec0edf
2 changed files with 35 additions and 3 deletions

View File

@@ -54,6 +54,14 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import reactor.core.publisher.Mono;
/**
* Default reactive implementation of a {@link StateMachineExecutor}.
*
* @author Janne Valkealahti
*
* @param <S> the type of state
* @param <E> the type of event
*/
public class ReactiveStateMachineExecutor<S, E> extends LifecycleObjectSupport implements StateMachineExecutor<S, E> {
private static final Log log = LogFactory.getLog(ReactiveStateMachineExecutor.class);
@@ -66,15 +74,12 @@ public class ReactiveStateMachineExecutor<S, E> extends LifecycleObjectSupport i
private final Message<E> initialEvent;
private final TransitionComparator<S, E> transitionComparator;
private final TransitionConflictPolicy transitionConflictPolicy;
// TODO deferList is never cleared
private final Queue<Message<E>> deferList = new ConcurrentLinkedQueue<Message<E>>();
private final AtomicBoolean initialHandled = new AtomicBoolean(false);
private final StateMachineInterceptorList<S, E> interceptors = new StateMachineInterceptorList<S, E>();
private volatile Message<E> forwardedInitialEvent;
private volatile Message<E> queuedMessage = null;
private StateMachineExecutorTransit<S, E> stateMachineExecutorTransit;
private EmitterProcessor<TriggerQueueItem> triggerProcessor = EmitterProcessor.create(false);
private FluxSink<TriggerQueueItem> triggerSink;
private Flux<Void> triggerFlux;
@@ -215,6 +220,7 @@ public class ReactiveStateMachineExecutor<S, E> extends LifecycleObjectSupport i
if (StateMachineUtils.containsAtleastOne(source.getIds(), currentState.getIds())) {
if (trigger != null && trigger.evaluate(new DefaultTriggerContext<S, E>(queuedEvent.getPayload()))) {
deferList.remove(queuedEvent);
return Mono.just(new TriggerQueueItem(trigger, queuedEvent));
}
}

View File

@@ -365,6 +365,32 @@ public class EventDeferTests extends AbstractStateMachineTests {
assertThat(machine.getState().getIds(), contains("SUB2"));
}
@Test
public void testDeferEventCleared() throws Exception {
context.register(Config5.class);
context.refresh();
@SuppressWarnings("unchecked")
StateMachine<String, String> machine = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class);
machine.start();
assertThat(machine.getState().getIds(), containsInAnyOrder("S1"));
machine.sendEvent("E2");
assertThat(machine.getState().getIds(), containsInAnyOrder("S1"));
Object executor = TestUtils.readField("stateMachineExecutor", machine);
Collection<?> readField = TestUtils.readField("deferList", executor);
assertThat(readField.size(), is(1));
machine.sendEvent("E1");
assertThat(machine.getState().getIds(), containsInAnyOrder("S1"));
readField = TestUtils.readField("deferList", executor);
assertThat(readField.size(), is(0));
// deferred event handled so should not get back to S1
machine.sendEvent("E1");
assertThat(machine.getState().getIds(), containsInAnyOrder("S2"));
}
@Configuration
@EnableStateMachine
static class Config1 extends StateMachineConfigurerAdapter<String, String> {