spring-statemachine
spring-statemachine copied to clipboard
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