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 41, 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.