A saga can be built using the SagaBuilder
DSL.
This DSL is used to create saga actions, and define dependencies between them.
- Create a builder:
import io.simplesource.saga.client.dsl.SagaDSL; import static io.simplesource.saga.client.dsl.SagaDSL; SagaBuilder<A> sagaBuilder = SagaDSL.createBuilder();
- Define some actions:
SubSaga<A> a = sagaBuilder.addAction(actionIdA, actionCommandA, undoCommandA); SubSaga<A> b = sagaBuilder.addAction(actionIdB, actionCommandB, undoCommandB); SubSaga<A> c = sagaBuilder.addAction(actionIdC, actionCommandC, undoCommandC); ...
A
is the serializable action command type, typically something likeSpecificRecord
. -
Create dependencies between them:
Examples:
Execute
a
, thenb
, thenc
:a.andThen(b).andThen(c)
Execute
a
, thenb
,c
andd
in parallel, thene
:a.andThen(b).andThen(e) a.andThen(c).andThen(e) a.andThen(d).andThen(e)
This can also be expressed as:
a.andThen(inParallel(b, c, d)).andThen(e)
Execute
a
, thenb
,c
andd
in series, thene
. The following are equivalent:a.andThen(b).andThen(c).andThen(d).andThen(e) inSeries(a, b, c).andThen(d).andThen(e) inSeries(a, b, c, d, e) a.andThen(inSeries(b, c, d)).andThen(e) inSeries(List.of(a, b, c, d, e))
The latter is useful when we have a sequence of actions of length only known at runtime.
The
andThen
operator is associative. This means that the following are equivalent:a.andThen(b).andThen(c)
and
a.andThen(b.andThen(c))
This associativity property enables building larger sagas from smaller ones.
- Build the saga:
Result<SagaError, Saga<A>> sagaBuildResult = sagaBuilder.build();
If the Saga fails validation,such as has cyclical references or attempts to combine subsagas created with different builders, an error is created.
Scala DSL
A DSL is available for Scala users, loosely based on Akka Streams, equivalent to the Java DSL, but prettier and easier to read.
Examples:
a ~> b ~> c
a ~> inParallel(b, c, d) ~> e
a ~> List(b, c, d).inParallel ~> e