Skip to main content

On Enter and On Exit

What are they

Actions are fire-and-forget methods that are executed on state enter and exit.

Each state can have many onEnter and onExit actions.

You need to be sure that onEnter and onExit actions are light and fast. Avoid heavy and long running work there. For background and long running tasks you need to use either Service or Activity.

On Enter Actions

These actions are executed before services are started.

State state1 = new State("myState")
.WithActionOnEnter(() => {
// do some work on enter
})
.WithActionOnEnter(() => {
// do another work on enter
});

On Exit Actions

These actions are executed before services are exited. At this point all services are stopped.

State state1 = new State("myState")
.WithActionOnExit(() => {
// do some work before state exits
})
.WithActionOnExit(() => {
// do another work before state exits
});

Errors

If any action throws exception, the whole state machine is stopped with this exception. You must handle exceptions yourself.

Execution Order

Actions are executed one by one, the second action is not executed until the first not finished. The order of the execution is the same as the order of the actions registration.

For example:

State state1 = new State("myState")
.WithActionOnEnter(() => {
Console.WriteLine("Action 1");
})
.WithActionOnEnter(() => {
Console.WriteLine("Action 2");
})
.WithActionOnEnter(() => {
Console.WriteLine("Action 3");
});

If that state is executed within state machine, the console output would be:

Action 1
Action 2
Action 3

Awaitable Actions

Action can be awaitable. But in this case the state machine is not aware when the task is ended, because it has a standard Action signature with void return type. If you need to make sure your async code is finalized before next async code started, better to use it as a part of Service in the separate state.

info

Remember that Actions are state side effects and are not mandatory in state machine context.

The below example starts all actions at the same time one by one but not awaiting for their end, be careful by using awaitable code in actions, as it starts them one by one but executes in parallel.

// starting the stopwatch
Stopwatch watch = new Stopwatch();
watch.Start();

// creating the state with three on enter actions
// all of them are asyncronouse.
State state1 = new State("myState")
.WithActionOnEnter(async () => {
// in each action we wait for 10 seconds
await Task.Delay(10000);
Console.WriteLine("Action 1");
Console.WriteLine(watch.Elapsed);
})
.WithActionOnEnter(async () => {
await Task.Delay(10000);
Console.WriteLine("Action 2");
Console.WriteLine(watch.Elapsed);
})
.WithActionOnEnter(async () => {
await Task.Delay(10000);
Console.WriteLine("Action 3");
Console.WriteLine(watch.Elapsed);
});

// starting the state machine
var machine = new StateMachine("myMachine", "my machine", "myState", state1);
var interpreter = new Interpreter(machine);
// waiting untl machine is over
await interpreter.StartStateMachineAsync();

As a result, notice, that all of the actions were started one by one but not awaited by the interpreter while executing the state machine. Here is the result console output:

Action 3
Action 2
Action 1
00:00:10.0123988
00:00:10.0125964
00:00:10.0126358
caution

Notice, in async actions there is no guaranty on order execution, however they are started in the same order they were registered.