Deferred events are not handled in case the transition to the desired state was done by timerOnce
seems that if there are deferred events that are pending for a state and the state is reached by a timer (timeroonce) that these deferred events are not handled
Is this a bug?
Why attached a zip file? Better to add links to relevant code file, or not?
I wanted to send some example code, how do you normally do it?
package test;
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.config.StateMachineFactory; import org.springframework.statemachine.listener.StateMachineListenerAdapter; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import reactor.core.publisher.Mono;
import java.util.concurrent.BrokenBarrierException;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SimpleStateMachineConfiguration3.class) public class StateMachineTester3 {
@Autowired
private StateMachineFactory<String, String> stateMachineFactory;
@Test
public void testState1() throws InterruptedException, BrokenBarrierException {
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine("dddd" + i);
stateMachine.addStateListener(new StateMachineListenerAdapter<>() {
private StateContext<String, String> stateContext;
@Override
public void stateContext(StateContext<String, String> stateContext) {
this.stateContext = stateContext;
}
@Override
public void eventNotAccepted(Message<String> event) {
SimpleStateMachineConfiguration2.print("----------- EventNotAccepted: Payload: " + event.getPayload() + " state:" + stateContext.getStateMachine().getState().getId());
}
});
stateMachine.start();
stateMachine.sendEvent("E1"); // Start S1
// 1 MS --> S1->S2
Thread.sleep(2);
stateMachine.sendEvent(Mono.just(MessageBuilder.withPayload("E3").build())).subscribe(ret -> {
System.out.println(ret.getResultType()); // this event is deffered
});
Thread.sleep(100);
stateMachine.sendEvent(Mono.just(MessageBuilder.withPayload("E4").build())).subscribe(ret -> {
System.out.println(ret.getResultType()); // this event will
});
Thread.sleep(3000);
SimpleStateMachineConfiguration3.print("--- cur state = " + stateMachine.getState().getId() + " ---");
SimpleStateMachineConfiguration3.print("--- " + SimpleStateMachineConfiguration3.sum.get() + " ---");
Thread.sleep(1000);
}
}
package test;
import org.springframework.context.annotation.Configuration; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.EnableStateMachineFactory; import org.springframework.statemachine.config.StateMachineConfigurerAdapter; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import java.util.Arrays; import java.util.HashSet; import java.util.concurrent.atomic.AtomicInteger;
@Configuration @EnableStateMachineFactory public class SimpleStateMachineConfiguration3 extends StateMachineConfigurerAdapter<String, String> {
public static AtomicInteger sum = new AtomicInteger();
public static void print(String msg) {
System.out.println("[" + System.currentTimeMillis() + "][" + Thread.currentThread().getName() + "] " + msg);
}
public Action<String, String> printS2() {
return stateContext -> {
print("-----------s2?. " + stateContext.getStateMachine().getState().getId());
};
}
public Action<String, String> print(int i) {
return stateContext -> {
sum.incrementAndGet();
print("----------- cur state. " + i + " " + stateContext.getStateMachine().getState().getId());
};
}
@Override
public void configure(StateMachineStateConfigurer<String, String> states)
throws Exception {
states.withStates()
.initial("START")
.end("END")
.states(new HashSet<>(Arrays.asList("S1", "S2", "S3")))
.state("S1", "E3")
;
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("START").target("S1").event("E1").and()
.withExternal()
.source("S1").target("S2").timerOnce(10)
.action(printS2())
.and()
.withExternal()
.source("S2").target("S3").event("E3").action(print(3))
.and()
.withExternal()
.source("S2").target("S2").event("E4").action(print(4)) // this is just to trigger the deferred event
;
}
}
The best thing is to create a project on GitHub and share it.
https://github.com/maayanhope/statemachinedeferredtest/tree/main/src