shrink0r/workflux

Initial state options variables

MrHash opened this issue · 11 comments

Is it possible to mutable execution context options from an initial state which are visible to following states?

Yes, it is.
Use can use the VariableState for this:

<?xml version="1.0" encoding="UTF-8" ?>

<state_machines xmlns="urn:schemas-workflux:statemachine:0.5.0">
    <state_machine name="video_transcoding" class="Workflux\StateMachine\EventEmittingStateMachine">
        <initial name="new" class="Workflux\State\VariableState">
            <option name="varibales"> <!-- will be added onEntry -->
                <option name="foo">bar</option>
                <option name="wat">42</option>
            </option>
            <option name="remove_varibales"><!-- will be removed onExit -->
                <option>foo</option>
            </option>
        </initial>
    </state_machine>
</state_machines>

In the example the variable bar will be available on states entered after new.

Having a problem with this kind of configuration. I think it maybe because the transitions are validated before the onEntry variables are set?

<?xml version="1.0" encoding="UTF-8" ?>

<state_machines xmlns="urn:schemas-workflux:statemachine:0.5.0">
    <state_machine name="uzi_9mm" class="Workflux\StateMachine\EventEmittingStateMachine">

        <initial name="waiting" class="Workflux\State\VariableState">
            <event name="start">
                <transition target="downloading" />
            </event>
            <option name="variables">
                <option name="downloading_required">true</option>    
                <option name="validating_required">true</option>    
            </option>
        </initial>

        <state name="downloading">
            <transition target="validating">
                <guard class="Workflux\Guard\ExpressionGuard">
                    <option name="expression">params.validating_required</option>
                </guard>
            </transition>
        </state>

        <state name="validating" class="Workflux\State\VariableState">
            <transition target="finished" />
            <option name="variables">
                <option name="downloading_required">false</option>    
            </option>
        </state>

        <final name="finished" />

    </state_machine>
</state_machines>

can you describe the problem please?
what is the expected behavior?
what is currently happening?

P.S.:
Instead of the ExpressionGuard you can use the VariableGuard, so you don't explicitly have to use the params variable within the expression.

<state name="downloading">
        <transition target="validating">
                <guard class="Workflux\Guard\VariableGuard">
                    <option name="expression">validating_required</option>
                </guard>
        </transition>
</state>

I'm getting this error: Transition for event "_sequential" at state "downloading" was rejected. Presumably because the param was not found in the context during building. I guess using the VariableGuard would make sense in this case.

I'll wildly assume that you are manually initializeing the execution context's current_state setting it to waiting?
If so, then onEntry is not triggered on the waiting state.
The state is then considered to already have been entered and transition callbacks are only invoked once per transition.
You do not need to initially set the current_state.
The state machine will start from the beginning if no current_state can be resolved upon a given subject.

Ah yeh that looks like the problem. Passing null for $current_state_name in the ExecutionContext constructor and it works. Would it not be good to trigger the onEntry for the specified state if provided?

Actually that is how it initially was implemented.
I changed the behavior in order to have a single execution guarantee for the transition callbacks.
For example if you send an email onEntry, you wouldn't the email to be sent twice.
This is what would happen if onEntry would be called on a given state, in some cases.

In the below example the approval.onEntry would be called twice:

  • when entered coming from the new state
  • when resumed before leaving to the published state
<state_machines xmlns="urn:schemas-workflux:statemachine:0.4.0">
    <state_machine name="four_eye">
        <initial name="new">
            <event name="promote">
                <transition target="approval" />
            </event>
        </initial>
        <state name="approval">
            <event name="promote">
                <transition target="published" />
            </event>
        </state>
        <final name="published" />
    </state_machine>
</state_machines>

Yeh i guess if the state failed it would trigger onEntry a second time on retry. Makes sense. How about making the $current_state_name default to null in the constructor then?

✔️

I'll merge and release the stuff as soon as you approve, that it's working for you now.

I'm closing this one, as an answer was found.
@MrHash For further feedback, please continue with #25