Fix infinite loop after resetting state machine #1151
      
        
          +59
        
        
          −1
        
        
          
        
      
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Glossary
Description of unit test state names:
S8_1- itintial stateS8_2- custom start state that we pass with default contextS8_5- end stateS8_3,S8_4- transit statesProblem 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:
stopReactively;S8_2);startReactively;Expected behavior
Transitions from
S8_2toS8_5with state machine stopActual behavior
Infinite loop with transitions
S8_2 -> S8_3 -> S8_4 -> S8_5 -> S8_2 -> S8_3 -> ...as decribed in #1011What causes the problem
lastStatefield being filled with custom value that we passed in context (S8_2)S8_5)ReactiveStateMachineExecutorchecks triggerless transitions.spring-statemachine/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ReactiveStateMachineExecutor.java
Line 141 in 4495c7d
spring-statemachine/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ReactiveStateMachineExecutor.java
Lines 364 to 385 in 4495c7d
With not null
lastStatefield we'll get its value instead ofcurrentStatebecause ofisComplete()returningtrue.spring-statemachine/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java
Lines 184 to 194 in 4495c7d
Comparing
S8_2assourcewithS8_2ascurrentStatereturns true, causing this check to be skipped and transitiontnow passing to flatMap. This transition will be called again and again.spring-statemachine/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ReactiveStateMachineExecutor.java
Lines 373 to 375 in 4495c7d
Fix description
Main goal of this fix is guaranteed returning of
currentStatewhile state machine is in running life cycle.Triggerless state machines do all work inside
STARTINGstate duringstartReactivelycall, 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
getStatewill cause added test to run in infinite loop.