Polish docs
@@ -139,7 +139,7 @@ concepts.
|
||||
==== States
|
||||
A state is a model which a state machine can be in. It is always
|
||||
easier to describe state as a real world example rather than trying to
|
||||
abstract concepts with a generic documentation. For example lets take
|
||||
abstract concepts with a generic documentation. For example let's take
|
||||
a simple example of a keyboard most of us are using every single day.
|
||||
If you have a full keyboard which has normal keys on a left side and
|
||||
the numeric keypad on a right side you may have noticed that the
|
||||
@@ -303,7 +303,7 @@ other they must have a totally different states which means they are
|
||||
operating on different state machines.
|
||||
|
||||
It would be a little inconvenient to handle two different
|
||||
statemachines as totally separate entities because in a sense they are
|
||||
state machines as totally separate entities because in a sense they are
|
||||
still working together in a sense. This is why orthogonal regions can
|
||||
combine together a multiple simultaneous states within a single state
|
||||
in a state machine.
|
||||
@@ -314,12 +314,6 @@ in a state machine.
|
||||
This appendix provides more detailed technical documentation about
|
||||
using a Zookeeper with a Spring State Machine.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
This techical paper is work in progress and planned to be fully
|
||||
written towards `1.0.0.RELEASE`.
|
||||
====
|
||||
|
||||
=== Abstract
|
||||
Introducing a `distributed state` on top of a single state machine
|
||||
instance running on a single `jvm` is a difficult and a complex topic.
|
||||
@@ -351,7 +345,7 @@ a need to explicitly build these distributed state concepts.
|
||||
Spring State Machine is not forced to use a single threaded execution
|
||||
model because once multiple regions are uses, regions can be executed
|
||||
parallel if necessary configuration is applied. This is an important
|
||||
topic because once user wants to have a paraller state machine
|
||||
topic because once user wants to have a parallel state machine
|
||||
execution it will make state changes faster for independent regions.
|
||||
|
||||
When state changes are no longer driven by a trigger in a local jvm or
|
||||
@@ -463,7 +457,7 @@ where state machine is run. Essentially every state machine sample
|
||||
will connect to local `Zookeeper` instance which allows use, via
|
||||
`jepsen` to simulate network conditions.
|
||||
|
||||
Plotted graps below in this chapter contain states and events which
|
||||
Plotted graphs below in this chapter contain states and events which
|
||||
directly maps to a state chart which can be found from
|
||||
<<statemachine-examples-web>>.
|
||||
|
||||
@@ -543,11 +537,11 @@ brain split will create a minority and majority partitions of an
|
||||
ensemble where hosts in a minority cannot participate in an ensemble
|
||||
anymore until network status has been healed.
|
||||
|
||||
In below tests we will demostrate that various types of brain-split's in
|
||||
In below tests we will demonstrate that various types of brain-split's in
|
||||
an ensemble will eventually cause fully synchronized state of all
|
||||
distributed state machines.
|
||||
|
||||
There are two scenarious having a one straight brain split in a
|
||||
There are two scenarios having a one straight brain split in a
|
||||
network where where `Zookeeper` and `Statemachine` instances are
|
||||
split in half, assuming each `Statemachine` will connect into a
|
||||
local `Zookeeper` instance:
|
||||
@@ -556,21 +550,21 @@ local `Zookeeper` instance:
|
||||
connected into majority will keep functioning properly.
|
||||
* If current zookeeper leader is left in minority, all clients will
|
||||
disconnect from it and will try to connect back till previous
|
||||
minority members has succesfully joined back to existing majority
|
||||
minority members has successfully joined back to existing majority
|
||||
ensemble.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
In our current `jepsen` tests we can't separate zookeeper split brains
|
||||
scenarios between leader left in marojity or minority so we need to
|
||||
scenarios between leader left in majority or minority so we need to
|
||||
run tests multiple time to accomplish this situation.
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
In below plots we have mapped a state machine error state into a
|
||||
In below plots we have mapped a state machine error state into an
|
||||
`error` to indicate that `state machine` is in error state instead or
|
||||
a normal state. Please indicate this when interpering chart states.
|
||||
a normal state. Please indicate this when interpreting chart states.
|
||||
====
|
||||
|
||||
In this first test we show that when existing zookeeper leader was
|
||||
@@ -581,7 +575,7 @@ What's happening in above chart:
|
||||
|
||||
* First event `C` is sent to all machine leading a state change to
|
||||
`S211`.
|
||||
* Jepsen nemisis will cause a brain-split which is causing partitions
|
||||
* Jepsen nemesis will cause a brain-split which is causing partitions
|
||||
of `n1/n2/n5` and `n3/n4`. Nodes `n3/n4` are left in minority and
|
||||
nodes `n1/n2/n5` construct a new healthy majority. Nodes in
|
||||
majority will keep function without problems but nodes in minority
|
||||
@@ -600,7 +594,7 @@ What's happening in above chart:
|
||||
|
||||
* First event `C` is sent to all machine leading a state change to
|
||||
`S211`.
|
||||
* Jepsen nemisis will cause a brain-split which is causing partitions
|
||||
* Jepsen nemesis will cause a brain-split which is causing partitions
|
||||
so that existing `Zookeeper` leader is kept in minority and all
|
||||
instances are disconnected from ensemble.
|
||||
* Jepsen will heal network and after some time all nodes will join
|
||||
@@ -610,7 +604,7 @@ What's happening in above chart:
|
||||
`S21`.
|
||||
|
||||
==== Crash and Join Tolerance
|
||||
In this test we will demostrate that killing existing state machine
|
||||
In this test we will demonstrate that killing existing state machine
|
||||
and then joining new instance back into an ensemble will keep the
|
||||
distributed state healthy and newly joined state machines will synchronize
|
||||
their states properly.
|
||||
|
||||
@@ -14,7 +14,7 @@ There are few choices a state machine developer can choose.
|
||||
* Implement an action and send appropriate event into a state machine
|
||||
which triggers a transition into a proper target state.
|
||||
* Define deferred event within a state and before sending an event
|
||||
send a event which will be deferred and thus causing next
|
||||
send an event which will be deferred and thus causing next
|
||||
appropriate state transition when it is more convenient to handle
|
||||
that event.
|
||||
* Implement a triggerless transition which will automatically cause
|
||||
|
||||
@@ -202,7 +202,7 @@ production development.
|
||||
====
|
||||
|
||||
== Developing your first Spring Statemachine application
|
||||
Lets start by creating a simple Spring Boot `Application` class
|
||||
Let's start by creating a simple Spring Boot `Application` class
|
||||
implementing `CommandLineRunner`.
|
||||
|
||||
[source,java,indent=0]
|
||||
|
||||
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 99 KiB |
@@ -3,7 +3,7 @@
|
||||
Concept of a state machine is most likely older that any of a reader
|
||||
of this reference documentation and definitely older than a Java
|
||||
language itself. Description of finite automate dates back to 1943
|
||||
when gentlements Warren McCulloch and Walter Pitts wrote a paper about
|
||||
when gentlemens Warren McCulloch and Walter Pitts wrote a paper about
|
||||
it. Later George H. Mealy presented a state machine concept in 1955
|
||||
which is known as a Mealy Machine. A year later in 1956 Edward F.
|
||||
Moore presented another paper which is known as a Moore Machine. If
|
||||
|
||||
@@ -64,7 +64,7 @@ tasks execution errors and then having a way to continue execution
|
||||
without executing already successfully executed tasks. Addition to
|
||||
this it would be nice if some execution errors can be handled
|
||||
automatically and as a last fallback, if error can't be handled
|
||||
automatically, state maching is put into a state where user can handle
|
||||
automatically, state machine is put into a state where user can handle
|
||||
errors manually.
|
||||
|
||||
`TasksHandler` contains a builder method to configure handler instance
|
||||
@@ -90,7 +90,7 @@ include::samples/DocsTasksSampleTests.java[tags=snippetB]
|
||||
|
||||
Order to listen what is happening with a task execution an instance of
|
||||
a `TasksListener` can be registered with a `TasksHandler`. Recipe
|
||||
provides an adapter `TasksListenerAdapter` if you dont' want to
|
||||
provides an adapter `TasksListenerAdapter` if you don't want to
|
||||
implement a full interface. Listener provides a various hooks to
|
||||
listen tasks execution events.
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ include::samples/demo/showcase/Application.java[tags=snippetD]
|
||||
include::samples/demo/showcase/Application.java[tags=snippetE]
|
||||
----
|
||||
|
||||
Lets go through what this state machine do when it's executed and we
|
||||
Let's go through what this state machine do when it's executed and we
|
||||
send various event to it.
|
||||
|
||||
[source,text]
|
||||
@@ -229,9 +229,9 @@ user can open a deck, insert or change a disk, then drive player
|
||||
functionality by pressing various buttons like _eject_, _play_,
|
||||
_stop_, _pause_, _rewind_ and _backward_.
|
||||
|
||||
How many of use have really given a thought of what it will take to
|
||||
How many of us have really given a thought of what it will take to
|
||||
make a code for a CD Player which interacts with a hardware. Yes,
|
||||
concept of a player is overly simple but if you look behind a scenes
|
||||
concept of a player is overly simple but if you look behind the scenes
|
||||
things actually get a bit convoluted.
|
||||
|
||||
You've probably noticed that if your deck is open and you press play,
|
||||
@@ -246,7 +246,7 @@ really want to keep adding more flags and if/else clauses.
|
||||
|
||||
image::images/statechart3.png[width=500]
|
||||
|
||||
Lets go through how this sample and its state machine is designed and
|
||||
Let's go through how this sample and its state machine is designed and
|
||||
how those two interacts with each other. Below three config sections
|
||||
are used withing a _EnumStateMachineConfigurerAdapter_.
|
||||
|
||||
@@ -371,7 +371,7 @@ include::samples/demo/cdplayer/Application.java[tags=snippetL]
|
||||
----
|
||||
|
||||
One other important aspect of a state machines is that they have their
|
||||
own responsibilies mostly around handling states and all application
|
||||
own responsibilities mostly around handling states and all application
|
||||
level logic should be kept outside. This means that application needs
|
||||
to have a ways to interact with a state machine and below sample is
|
||||
how cdplayer does it order to update lcd status. Also pay attention
|
||||
@@ -397,7 +397,7 @@ matched from enums. _@StatesOnTransition_ is then something what user
|
||||
can create into his own application to get a type safe annotation where
|
||||
a real enums can be used.
|
||||
|
||||
Lets see an example how this state machine actually works.
|
||||
Let's see an example how this state machine actually works.
|
||||
|
||||
[source,text]
|
||||
----
|
||||
@@ -539,7 +539,7 @@ regions are executed parallel.
|
||||
include::samples/demo/tasks/Application.java[tags=snippetAE]
|
||||
----
|
||||
|
||||
Lets see an examples how this state machine actually works.
|
||||
Let's see an examples how this state machine actually works.
|
||||
|
||||
[source,text]
|
||||
----
|
||||
@@ -682,7 +682,7 @@ include::samples/demo/washer/Application.java[tags=snippetAA]
|
||||
include::samples/demo/washer/Application.java[tags=snippetAB]
|
||||
----
|
||||
|
||||
Lets see an example how this state machine actually works.
|
||||
Let's see an example how this state machine actually works.
|
||||
[source,text]
|
||||
----
|
||||
sm>sm start
|
||||
@@ -726,7 +726,7 @@ What happened in above run:
|
||||
[[statemachine-examples-persist]]
|
||||
== Persist
|
||||
Persist is a sample using recipe <<statemachine-recipes-persist>> to
|
||||
demonstate how a database entry update logic can be controlled by a
|
||||
demonstrate how a database entry update logic can be controlled by a
|
||||
state machine.
|
||||
|
||||
The state machine logic and configuration is shown above:
|
||||
@@ -854,7 +854,7 @@ with `CuratorFramework` client.
|
||||
include::samples/demo/zookeeper/Application.java[tags=snippetB]
|
||||
----
|
||||
|
||||
Lets go through a simple example where two different shell instances are
|
||||
Let's go through a simple example where two different shell instances are
|
||||
started with command `java -jar
|
||||
spring-statemachine-samples-zookeeper-1.0.0.BUILD-SNAPSHOT.jar`.
|
||||
|
||||
@@ -928,11 +928,11 @@ image::images/statechart11.png[width=500]
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Due to nature of this sample an instanse of a `Zookeeper` is expected to
|
||||
Due to nature of this sample an instance of a `Zookeeper` is expected to
|
||||
be available from a localhost for every individual sample instance.
|
||||
====
|
||||
|
||||
Lets go through a simple example where three different sample instances are
|
||||
Let's go through a simple example where three different sample instances are
|
||||
started with command `java -jar
|
||||
spring-statemachine-samples-web-1.0.0.BUILD-SNAPSHOT.jar`. If you are
|
||||
running different instances on a same host you need to distinguish
|
||||
@@ -962,9 +962,9 @@ denoted by transition associated with an event `C`.
|
||||
|
||||
image::images/sm-dist-n2-2.png[width=500]
|
||||
|
||||
Then lets press button `Event H` and what is supposed to happen is
|
||||
Then let's press button `Event H` and what is supposed to happen is
|
||||
that internal transition is executed on all state machines changing
|
||||
extended stare variable `foo` from value `0` to `1`. This change is
|
||||
extended state variable `foo` from value `0` to `1`. This change is
|
||||
first done on a state machine receiving the event and then propagated
|
||||
to other state machines. You should only see variable `foo` to change
|
||||
from `0` to `1`.
|
||||
|
||||
@@ -54,7 +54,7 @@ away.
|
||||
[[statemachine-config]]
|
||||
=== Configuring States
|
||||
We'll get into more complex configuration examples a bit later but
|
||||
lets first start with a something simple. For most simple state
|
||||
let's first start with a something simple. For most simple state
|
||||
machine you just use `EnumStateMachineConfigurerAdapter` and define
|
||||
possible states, choose initial and optional end state.
|
||||
|
||||
@@ -128,9 +128,9 @@ In above two different types of guard configurations are used. Firstly a
|
||||
simple _Guard_ is created as a bean and attached to transition between
|
||||
states `S1` and `S2`.
|
||||
|
||||
Secondly a simple spel expression can be used as a guard where
|
||||
expression must return a `BOOLEAN` value. Behind a scenes this spel
|
||||
based guard is a _SpelExpressionGuard_. This was attached to
|
||||
Secondly a simple SPeL expression can be used as a guard where
|
||||
expression must return a `BOOLEAN` value. Behind a scenes this
|
||||
expression based guard is a _SpelExpressionGuard_. This was attached to
|
||||
transition between states `S2` and `S3`. Both guard in above sample
|
||||
always evaluate to true.
|
||||
|
||||
@@ -354,9 +354,9 @@ requirement to work via Spring `@Configuration` classes and
|
||||
application context. While this is a very clear model to configure a
|
||||
state machine instances it will limit configuration at a compile time
|
||||
which is not always what a user wants to do. If there is a requirement
|
||||
to build more dynamic state machines, a simple builder patter can be
|
||||
to build more dynamic state machines, a simple builder pattern can be
|
||||
used to construct similar instances. Using strings as states and
|
||||
events this builder patter can be used to build fully dynamic state
|
||||
events this builder pattern can be used to build fully dynamic state
|
||||
machines outside of a Spring application context as shown above.
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -450,7 +450,7 @@ expression as an argument.
|
||||
== Using Extended State
|
||||
Let's assume that we'd need to create a state machine tracking how
|
||||
many times a user is pressing a key on a keyboard and then terminate
|
||||
when keys are pressed 1000 times. Possible but a really dump solution
|
||||
when keys are pressed 1000 times. Possible but a really naive solution
|
||||
would be to create a new state for each 1000 key presses. Going
|
||||
even worse combinations you might suddenly have astronomical number of
|
||||
states which naturally is not very practical.
|
||||
@@ -594,7 +594,7 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetM]
|
||||
----
|
||||
|
||||
=== Limitations and Problems
|
||||
Spring application context is not a fastest event bus out there so it
|
||||
Spring application context is not a fastest eventbus out there so it
|
||||
is advised to give some thought what is a rate of events state machine
|
||||
is sending. For better performance it may be better to use
|
||||
_StateMachineListener_ interface. For this specific reason it is
|
||||
@@ -619,7 +619,7 @@ into your beans.
|
||||
|
||||
=== Annotation Support
|
||||
_@WithStateMachine_ annotation can be used to associate a state
|
||||
machine with a existing bean. Withing this annotation a propertys
|
||||
machine with a existing bean. Within this annotation a property's
|
||||
_source_ and _target_ can be used to qualify a transition
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -734,7 +734,7 @@ More about error handling shown in above example, see section
|
||||
== State Machine Error Handling
|
||||
If state machine detects an internal error during a state transition
|
||||
logic it may throw an exception. Before this exception is processed
|
||||
internally, user is given a change to intercept.
|
||||
internally, user is given a chance to intercept.
|
||||
|
||||
Normal `StateMachineInterceptor` can be used to intercept errors and
|
||||
example of it is shown above.
|
||||
@@ -836,7 +836,7 @@ 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 enought information to reset a
|
||||
`StateMachineContext` which contains enough information to reset a
|
||||
`StateMachine`.
|
||||
|
||||
While `Distributed State Machine` is implemented via an abstraction,
|
||||
@@ -884,7 +884,7 @@ steps into a plan and during these steps you can send events and check
|
||||
various conditions like state changes, transitions and extended state
|
||||
variables.
|
||||
|
||||
Lets take a simple `StateMachine` build using below example:
|
||||
Let's take a simple `StateMachine` build using below example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
|
||||