dotnet-state-machine / stateless

A simple library for creating state machines in C# code
Other
5.6k stars 766 forks source link

Question - How to return to correct previous state? #497

Closed flycast closed 1 year ago

flycast commented 1 year ago

I have a workflow where there is a state that can be transitioned to from 5 different states.

A => flexible B => flexible C => flexible D => flexible E => flexible

When flexible is finished running I want to transition back to the state that transitioned to it. In other words if state "A" transitions to flexible I want to return to "A" when "flexible is finished. What is the design pattern for saving the previous state and making sure I return to the previous state?

Examining my state machine variable I do not see a direct property that holds the previous state value. I suppose I could use the "OnTransitioned" callback to save a variable value that stores the previous state but that seems a little bit error prone?

_stateMachine.OnTransitioned(t => StateTransitioned(t.Trigger, t.Source, t.Destination));

And then in StateTransitioned:

    private void StateTransitioned(AppTransitions trigger, AppState source, AppState destination)
    {
        lastState = source;

Then I could return to `lastState when "flexible" is finished.

What is best way to make sure I return to previous state?

mclift commented 1 year ago

What you've proposed above seems like a good approach for this, and I don't see why it would be error prone. Having recorded the from state in the transitions to flexible, you'd configure a dynamic transition from flexible that would select A, B, C, D or E as the target state based on your selection logic.

The README doesn't currently have any examples of PermitDynamic, but there are some unit tests that you could use for reference in DynamicTriggerBehaviourFixture.cs.

Otherwise—and this is a little clunky—you could split flexible into five different states configured with transitions explicitly back to the last state, like A => flexibleA => A, B => flexibleB => B, etc.

flycast commented 1 year ago

Otherwise—and this is a little clunky—you could split flexible into five different states configured with transitions explicitly back to the last state, like A => flexibleA => A, B => flexibleB => B, etc.

Yeah, that's how I started. It's pretty ugly. That is why I was looking for a better solution.

mclift commented 1 year ago

Got it. Do you think the PermitDynamic approach will work for you? One downside with PermitDynamic is the transitions probably won't show up in the DOT graph representation if that's a feature you're using.

flycast commented 1 year ago

I am getting close on this. What is a guard clause?

mclift commented 1 year ago

Ohh, guard clauses are probably your answer. I'd thought about them before but discounted the idea thinking their intent was to allow/disallow a given transition, but now I've looked at it again I realise their main use case it to let you choose from a limited set of possible transitions via some condition.

https://github.com/dotnet-state-machine/stateless#guard-clauses

Also see examples in the unit tests: https://github.com/dotnet-state-machine/stateless/blob/b95a785fb53b95e0c8cbcf587fdab9317d69708d/test/Stateless.Tests/StateMachineFixture.cs#L162

flycast commented 1 year ago

Guard is actually working much better. Thanks for your help!

None of us are as smart as all of us!