Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StateMachinePersister is working inconsistently with orthogonal regions #1150

Open
manhnt217 opened this issue Mar 17, 2024 · 1 comment
Open
Labels
status/need-triage Team needs to triage and take a first look

Comments

@manhnt217
Copy link

Hi, I'm new to Spring state machine.

Recently I'm testing persistence support of the framework and I found this issue.

My testing is pretty much similar to this example Using StateMachinePersister except that I'm using a state machine with 2 orthogonal regions (named LEFT, RIGHT). It looks like below

State diagram

I first start machine1 and then send these events: START, EL1, EL2 (in this order) to it. Now machine1.getState().getIds() give me the result [LR, L1, R1] (which is correct).

Then after transfering (persist/restore) the state of machine1 into machine2, I check the state of machine2 and receive the result [LR, L1, R1] (which is still correct).

Then I send ER1 to both machines then check the results. I realize that they are different:

  • machine1.getState().getIds() = [E]
  • machine2.getState().getIds() = [LR, L1, R2]

I don't know which one (machine1 or machine1) behave correctly (because I was asking this question a few days ago on stackoverflow . But it seems like the persister did not "fully transfer" the state from machine1 to machine2.

Below is the code that I am using:

       machine1.startReactively().block();

       machine1.sendEvents(Flux.just(
               SMConfig.MEvent.START,
               SMConfig.MEvent.EL1,
               SMConfig.MEvent.EL2
       ).map(p -> MessageBuilder.withPayload(p).build())).blockLast();

       log.info("---- SM1 state = {}", machine1.getState().getIds());

       persister.persist(machine1, "myid");
       persister.restore(machine2, "myid");

       log.info("SM2 state = {}", machine2.getState().getIds());

       machine1.sendEvents(Flux.just(
               SMConfig.MEvent.ER1
       ).map(p -> MessageBuilder.withPayload(p).build())).blockLast();

       log.info("---- SM1 state = {}", machine1.getState().getIds());

       machine2.sendEvents(Flux.just(
               SMConfig.MEvent.ER1
       ).map(p -> MessageBuilder.withPayload(p).build())).blockLast();

       log.info("SM2 state = {}", machine2.getState().getIds());

and the machine configuration

    @Override
    public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
        states.withStates()
                .initial(I)
                .fork(FORK)
                .state(LR)
                .join(JOIN)
                .state(E)
                .and().withStates().parent(LR)
                    .region("LEFT")
                        .initial(R1)
                        .state(R2)
                .and().withStates().parent(LR)
                    .region("RIGHT")
                        .initial(L1)
                        .state(L2);
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
        transitions
                        .withExternal()          .source(I)            .target(FORK)              .event(START)
                .and()
                        .withFork()              .source(FORK)             .target(LR)
                .and()
                        .withExternal()          .source(L1)            .target(L2)             .event(EL1)
                .and()
                        .withExternal()          .source(L2)            .target(L1)             .event(EL2)
                .and()
                        .withExternal()          .source(R1)            .target(R2)             .event(ER1)
                .and()
                        .withExternal()          .source(R2)            .target(R1)             .event(ER2)
                .and()
                        .withJoin()              .source(R2).source(L2) .target(JOIN)
                .and()
                        .withExternal()          .source(JOIN)             .target(E)
                .and()
                        .withExternal()          .source(E)             .target(I)             .event(RESET)
                ;
    }

Thank you for your time!

@github-actions github-actions bot added the status/need-triage Team needs to triage and take a first look label Mar 17, 2024
@manhnt217
Copy link
Author

manhnt217 commented Mar 17, 2024

Debugging into the code, I see that JoinTracker does not get populated the correct state if the state machine is being restored from persistent context. Or in another word, the state of JoinTracker doesn't get persisted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/need-triage Team needs to triage and take a first look
Projects
None yet
Development

No branches or pull requests

1 participant