Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix infinite loop after resetting state machine #1151

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

Open
radmirr wants to merge 1 commit into spring-projects:main
base: main
Choose a base branch
Loading
from radmirr:fix-restore-infinite-loop

Conversation

@radmirr
Copy link

@radmirr radmirr commented Mar 17, 2024

Glossary

Description of unit test state names:
S8_1 - itintial state
S8_2 - custom start state that we pass with default context
S8_5 - end state
S8_3, S8_4 - transit states

Problem description

In some situations (e.g. app crash) we need to start state machine from custom state in order to resume execution. To do that we are following next steps:

  1. Stop state machine with stopReactively;
  2. Reset via accessor with default context and specified state (S8_2);
  3. Start machine with startReactively;

Expected behavior

Transitions from S8_2 to S8_5 with state machine stop

Actual behavior

Infinite loop with transitions S8_2 -> S8_3 -> S8_4 -> S8_5 -> S8_2 -> S8_3 -> ... as decribed in #1011

What causes the problem

  1. Resetting state machine leads to lastState field being filled with custom value that we passed in context (S8_2)
  2. After exiting from last state (S8_5) ReactiveStateMachineExecutor checks triggerless transitions.
  1. In normal scenarios this filter must return false and state machine must stop.
.filter(t -> {
State<S,E> source = t.getSource();
if (source == null) {
return false;
}
State<S,E> currentState = stateMachine.getState();
if (currentState == null) {
return false;
}
if (!StateMachineUtils.containsAtleastOne(source.getIds(), currentState.getIds())) {
return false;
}
if (transitionConflictPolicy != TransitionConflictPolicy.PARENT && completion != null
&& !source.getId().equals(completion.getId())) {
if (source.isOrthogonal()) {
return false;
} else if (!StateMachineUtils.isSubstate(source, completion)) {
return false;
}
}
return true;
})
  1. With not null lastState field we'll get its value instead of currentState because of isComplete() returning true.

    @Override
    public State<S,E> getState() {
    // if we're complete assume we're stopped
    // and state was stashed into lastState
    State<S, E> s = lastState;
    if (s != null && isComplete()) {
    return s;
    } else {
    return currentState;
    }
    }
  2. Comparing S8_2 as source with S8_2 as currentState returns true, causing this check to be skipped and transition t now passing to flatMap. This transition will be called again and again.

    if (!StateMachineUtils.containsAtleastOne(source.getIds(), currentState.getIds())) {
    return false;
    }

Fix description

Main goal of this fix is guaranteed returning of currentState while state machine is in running life cycle.
Triggerless state machines do all work inside STARTING state during startReactively call, so we can count it as a part of running life cycle.

Existing tests was not affected by this change and passed successfully.

Commenting running check from getState will cause added test to run in infinite loop.

Copy link

@radmirr Please sign the Contributor License Agreement!

Click here to manually synchronize the status of this Pull Request.

See the FAQ for frequently asked questions.

Copy link

@radmirr Thank you for signing the Contributor License Agreement!

Copy link

@alexfern252 alexfern252 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me. thanks.

Copy link

libinbin880521 commented Nov 6, 2025 via email

这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

1 more reviewer

@alexfern252 alexfern252 alexfern252 approved these changes

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Resetting spring state machine results in infinite loop

AltStyle によって変換されたページ (->オリジナル) /