Distributed state is probably one of a most complicated concepts of a Spring State Machine. What exactly is a distributed state? A state within a single state machine is naturally really simple to understand but when there is a need to introduce a shared distributed state through a state machines, things will get a little complicated.
![]() | Note |
|---|---|
|
Distributed state functionality is still a preview feature and is not yet considered to be stable in this particular release. We expect this feature to mature towards the first official release. |
For generic configuration support see section Section 10.9, “Configuring Common Settings” and actual usage example see sample Chapter 42, Zookeeper.
Distributed State Machine is implemented via a
DistributedStateMachine class which simply wraps an actual instance
of a StateMachine. DistributedStateMachine intercepts
communication with a StateMachine instance and works with
distributed state abstractions handled via interface
StateMachineEnsemble. Depending on an actual implementation
StateMachinePersist interface may also be used to serialize a
StateMachineContext which contains enough information to reset a
StateMachine.
While Distributed State Machine is implemented via an abstraction,
only one implementation currently exists based on Zookeeper.
Here is a generic example of how Zookeeper based Distributed State
Machine would be configured.
@Configuration @EnableStateMachine public class Config extends StateMachineConfigurerAdapter<String, String> { @Override public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception { config .withDistributed() .ensemble(stateMachineEnsemble()) .and() .withConfiguration() .autoStartup(true); } @Override public void configure(StateMachineStateConfigurer<String, String> states) throws Exception { // config states } @Override public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception { // config transitions } @Bean public StateMachineEnsemble<String, String> stateMachineEnsemble() throws Exception { return new ZookeeperStateMachineEnsemble<String, String>(curatorClient(), "/zkpath"); } @Bean public CuratorFramework curatorClient() throws Exception { CuratorFramework client = CuratorFrameworkFactory .builder() .defaultData(new byte[0]) .connectString("localhost:2181").build(); client.start(); return client; } }
Current technical documentation of a Zookeeker based distributed
state machine can be found from an appendice Appendix C, Distributed State Machine Technical Paper.
ZookeeperStateMachineEnsemble itself needs two mandatory settings,
an instance of curatorClient and basePath. Client is a
CuratorFramework and path is root of a tree in a Zookeeper.
Optionally it is possible to set cleanState which defaults to TRUE
and will clear existing data if no members exists in an ensemble. Set
this to FALSE if you want to preserve distributed state within
application restarts.
Optionally it is possible to set a size of a logSize which defaults
to 32 and is used to keep history of state changes. Value of this
setting needs to be a power of two. 32 is generally good default
value but if a particular state machine is left behind more than a
size of a log it is put into error state and disconnected from an
ensemble indicating it has lost its history to reconstruct fully
synchronized status.