Springboot Distributed State Machine
#statemachine
What is a distributed state?
An application may exist in a finite number of states. when something happens it takes your application from one state to the next. A state machine is driven by triggers, which are based on either events or timers.
Distributed property for state machines comes with an abstraction layer on top of default state machine implementation, for the time being, only one implementation exists which is based on Apache Zookeeper, a coordination service for distributed applications. More details .
How it works ?
- A distributed state machine is implemented through a DistributedStateMachine class that wraps an actual instance of a StateMachine.
- DistributedStateMachine intercepts communication with a StateMachine instance and works with distributed state abstractions handled through the StateMachineEnsemble interface.
- A ZookeeperStateMachineEnsemble needs two mandatory settings, an instance of curatorClient and a basePath. The client is a curotorClient which is an API for simplifying usage of Zookeeper functionalities and basePath which indicates the base zookeeper path -which will be used for creating znodes.
- When the zookeeper up and the statemachines are connected, znode can be queried either with built-in Zookeeper commands or CuratorFramework built-in methods
- Use the StateMachinePersist interface to serialize a StateMachineContext, which contains enough information to reset a StateMachine.
@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; } }
An Example Explaining it All
- Create two different application instances.
- Start INSTANCE_ONE .When first state machine is started, it is in its INITIAL_STATE. Then it sends an EVENT to transition into NEXT_STATE state.
- Start INSTANCE_TWO then starts start the second state machine. You should see that the NEXT_STATE
- From either INSTANCE_ONE or INSTANCE_TWO (say INSTANCE_TWO) send an ANOTHER_EVENT to transit NEXT_STATE into the FINAL_STATE state , you should see the state be changed if you check it from the INSTANCE_ONE.
References:
[1] https://docs.spring.io/spring-statemachine/docs/1.1.x/reference/html/sm-distributed.html
[2] https://docs.spring.io/spring-statemachine/docs/current/reference/#statemachine-examples-zookeeper
[3] https://ozdinc-celikel.medium.com/distributed-state-machines-using-java-spring-state-machine-framework-e9ff9655c486