Spring Statemachine Goes Reactive with 3.0.0.M1

Releases | Janne Valkealahti | August 08, 2019 | ...

I’m pleased to announce a first milestone release of a Spring Statemachine 3.0.0.M1 and with these words I can say that Statemachine is going reactive.

Statemachine itself would not need to be reactive for its own execution but as soon as machine steps outside of its controlled environment to execute user defined logic like Actions and Guards there is no guarantees that those features would not block.

Those using persisting features with a databases will benefit with reactive changes when that side of a world becomes more reactive. Essentially every time we need to take a step outside from a machine world we may hit blocking IO operations.

2.x line will be there for foreseeable future where 3.x will benefit from new changes. It really depends on a users how much new features are added to 2.x line.

In a 2.x machine execution is fully based on Spring TaskExecutor API. These executions takes machines from one state to the other. Along this execution various user level Actions are executed when states are entered or exited. Guards can be used to guard various transition paths and we don’t have no control what these do. TaskScheduler API is mostly used with triggering timers and executing Actions while being on a state.

As everything were based on TaskExecutor and TaskScheduler user were able to just switch these to something else to provide more parallel execution and scheduling which are usually needed when dealing with statemachine regions which needs to do execution in a parallel manner. All this made an internal threading model relatively complex and hours has been spent to track various race condition over the years.

Now that everyting is literally based on a Reactor and what it can do, this internal threading model has become much more reliable. We really don’t need to use locking anymore as Reactor will give us guarantees that its own flow execution simply works.

We have a new methods to interact reactively by using Mono and Flux of messages. Returned Flux then have more richer results what happened with a particular event. For example from a returned StateMachineEventResult it’s possible to check if event was accepted or deferred and which region handled it.

Flux<StateMachineEventResult<S, E>> sendEvent(Mono<Message<E>> event);
Flux<StateMachineEventResult<S, E>> sendEvents(Flux<Message<E>> events);

While in the old deprecated api you used something like:

boolean accepted = machine.sendEvent("EVENT");

Now nothing happens until you subscribe into returned Flux of StateMachineEventResult.

Message<String> event = MessageBuilder.withPayload("EVENT").build();

machine.sendEvent(Mono.just(event))
  .doOnComplete(() -> {
    System.out.println("Event handling complete");
  })
  .subscribe();

Same story continues with actions which is just a Function taking StateContext and returning a Mono.

public interface ReactiveAction<S, E>
  extends Function<StateContext<S, E>, Mono<Void>> {}

Same with guard expect you need to return a Boolean with a Mono.

public interface ReactiveGuard<S, E>
  extends Function<StateContext<S, E>, Mono<Boolean>> {}

Now is a good time to try it out and provide feedback for next milestones. I’d like to thank all the community contributions as some of the refactorings were relatively labour intensive.

Get the Spring newsletter

Thank you for your interest. Someone will get back to you shortly.

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring Runtime offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all