Bug: OMS does not execute onEnter-Events for some OrderItems

Hi, we discovered a Bug with OrderStateMachine::checkForEventRepetitions() when executing console oms:check-timeout

Expected behaviour: All OrderItems reach the desired states
Observed behaviour: Some OrderItems stay on states with onEnter-Events without executing these onEnter-Events. Also there are no Exceptions

How OrderStateMachine::checkForEventRepetitions() works:

  • is being executed every time OrderStateMachine::triggerEvent() is being executed
  • increases a eventName-counter by 1
  • returns false if the counter for the current event reaches 10
  • when false is returned, OrderStateMachine::triggerEvent() directly exits without triggering the current event

We discovered Bugs for this behaviour in three scenarios:

Scenario 1

Lets say:

  • we have 10 Orders with 1 OrderItem each => 10 OrderItems.
  • 9 in “timeout state 2”
  • 1 in “timeout state 1”
  • the timeouts for all of them are expired

Now we run console oms:check-timeout

  • lets say the 9 in “timeout state 2” are being processed first
  • “on enter event 2” is being processed 9 times
  • the counter for “on enter event 2” is set to 9

  • now the one in “timeout state 1” is being processed
  • “on enter event 1” is being executed 1 time
  • the counter for “on enter event 1” is set to 1
  • lets say: “condition 1” returns true
  • the item reaches “state 2”
  • tries to process “on enter event 2”
  • the counter for “on enter event 2” reaches 10
  • execution for this item stops
  • the item stays in “state 2” until we notice that it is there and manually trigger “on enter event 2”

Scenario 2

(I had to post the Image for this scenario as reply because of the “1 image per post for new users”-rule)

Basically the same, but this time we use the same events for different transitions:
Lets say:

  • we have 9 Orders with 1 OrderItem each => 9 OrderItems.
  • all 9 are in “timeout state 1”
  • the timeouts for all of them are expired

Now we run console oms:check-timeout

  • lets say for the first 8 in “timeout state 1” the condition “condition 1” is false
  • “check” is being processed 8 times
  • the counter for “check” is set to 8
  • these 8 return to “timeout state 1”

  • now the 9th item is being processes
  • “check” is being processed 1 more time
  • the counter for “check” is set to 9
  • lets say “condition 1” returns true this time
  • the item reaches “state 2”
  • tries to execute the onEnter-Event “check”
  • the counter for “check” reaches 10
  • execution for this item stops
  • the item stays in “state 2” until we notice that it is there and manually trigger “check”

Scenario 3

  • when having very much orders/items in such a timeout loop
  • AND these items usually leave the loop after 3 or 4 days
  • AND with console oms:check-timeout running every minute
  • THEN always only 9 of these orders/items are actually being processed per minute

  • IF more timeouts expire than being processed
  • THEN the older timeouts are not being processed at all
  • THEN they stay in their state until we manually trigger the event

The Image for Scenario 2

It’s sad that you got trap on this bug as well.
We noticed it a while ago, and the current solution is to “disable” checkForEventRepetitions:
Please override OrderStateMachine and place this piece there:

/**
 * @param string $eventId
 *
 * @return bool
 */
protected function checkForEventRepetitions($eventId): bool
{
    return true;
}