• Stars
    star
    268
  • Rank 148,413 (Top 3 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created about 7 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Example implementation of the Saga pattern for the classic trip booking example using the lightweight open source workflow engine (Camunda).

Saga example: trip booking

The Saga pattern describes how to solve distributed (business) transactions without two-phase-commit as this does not scale in distributed systems. The basic idea is to break the overall transaction into multiple steps or activities. Only the steps internally can be performed in atomic transactions but the overall consistency is taken care of by the Saga. The Saga has the responsibility to either get the overall business transaction completed or to leave the system in a known termination state. So in case of errors a business rollback procedure is applied which occurs by calling compensation steps or activities in reverse order. A more detailed look on Sagas is available in Saga: How to implement complex business transactions without two phaseย commit

In the example hotel, car and flight booking might be done by different remote services. So there is not technical transaction, but a business transaction. When the flight booking cannot be carried out succesfully you need to cancel hotel and car.

Saga example

Using Camunda you can implement the Saga either by using graphical modeling or by a Java DSL, called Model-API. As Camunda is very lightweight you can start the so called process engine, define the Saga and run instances by a couple of lines of Java code (if you use the default configuration and an in-memory H2 database), see TripBookingSaga.java:

public class TripBookingSaga {

  public static void main(String[] args) {
    // Configure and startup (in memory) engine
    ProcessEngine camunda = 
        new StandaloneInMemProcessEngineConfiguration()
          .buildProcessEngine();
    
    // define saga as BPMN process
    ProcessBuilder saga = Bpmn.createExecutableProcess("trip");
    
    // - flow of activities and compensating actions
    saga.startEvent()
        .serviceTask("car").name("Reserve car").camundaClass(ReserveCarAdapter.class)
          .boundaryEvent().compensateEventDefinition().compensateEventDefinitionDone()
          .compensationStart().serviceTask("car-compensate").name("Cancel car").camundaClass(CancelCarAdapter.class).compensationDone()
        .serviceTask("hotel").name("Book hotel").camundaClass(BookHotelAdapter.class)
          .boundaryEvent().compensateEventDefinition().compensateEventDefinitionDone()
          .compensationStart().serviceTask("hotel-compensate").name("Cancel hotel").camundaClass(CancelHotelAdapter.class).compensationDone()
        .serviceTask("flight").name("Book flight").camundaClass(BookFlightAdapter.class)
          .boundaryEvent().compensateEventDefinition().compensateEventDefinitionDone()
          .compensationStart().serviceTask("flight-compensate").name("Cancel flight").camundaClass(CancelFlightAdapter.class).compensationDone()
        .endEvent();
    
    // - trigger compensation in case of any exception (other triggers are possible)
    saga.eventSubProcess()
        .startEvent().error("java.lang.Throwable")
        .intermediateThrowEvent().compensateEventDefinition().compensateEventDefinitionDone()
        .endEvent();     

    // finish Saga and deploy it to Camunda
    camunda.getRepositoryService().createDeployment() //
        .addModelInstance("trip.bpmn", saga.done()) //
        .deploy();
    
    // now we can start running instances of our saga - its state will be persisted
    camunda.getRuntimeService().startProcessInstanceByKey("trip", Variables.putValue("name", "trip1"));
    camunda.getRuntimeService().startProcessInstanceByKey("trip", Variables.putValue("name", "trip2"));
  }

}

The real logic is attached as Java code by the adapter classes, e.g. the BookHotelAdapter.

The definition might look a bit verbose, as you have to use BPMN terminology. But you could write a thin SagaBuilder that improves readability of the Saga definition:

SagaBuilder saga = SagaBuilder.newSaga("trip")
        .activity("Reserve car", ReserveCarAdapter.class) 
        .compensationActivity("Cancel car", CancelCarAdapter.class) 
        .activity("Book hotel", BookHotelAdapter.class) 
        .compensationActivity("Cancel hotel", CancelHotelAdapter.class) 
        .activity("Book flight", BookFlightAdapter.class) 
        .compensationActivity("Cancel flight", CancelFlightAdapter.class) 
        .end()
        .triggerCompensationOnAnyError();

camunda.getRepositoryService().createDeployment() 
        .addModelInstance(saga.getModel()) 
        .deploy();

The engine will take care of state handling, compensation and could also handle timeouts and escalations.

In real-life scenarios you might configure and run the Camunda engine differently, e.g. by using Spring or Spring Boot. In this example you can also use the Spring Boot Application in order to fire the application up - and afterwords even connect Camundas visual tooling.

A visual representation is automatically created in the background by Camunda. (You need to use Camunda in a version >= 7.8.0.)

Cockpit Screenshot

The flow can also be modeled graphically instead of using the Model API. In this case use the Camunda Modeler to draw the BPMN notation:

Compensation in BPMN

The trip.bpmn (BPMN model file)

Get started

You need

  • Java
  • Maven

Required steps

  • Checkout or download this project
  • Run the Application.java class as this is a Spring Boot application running everything at once, starting exactly one Saga that is always "crashing" in the flight booking
  • If you like you can access the Camunda database from the outside, e.g. using the "Camunda Standalone Webapp" to inspect state. Use the follwing connection url: jdbc:h2:tcp://localhost:8092/mem:camunda;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE. Note that you need Camunda Enterprise to see historical data.

As an alternative:

  • Run the TripBookingSaga.java class via your favorite IDE - it also will run instances of the Saga without requiring any infrastructure

More Repositories

1

flowing-retail

Sample application demonstrating an order fulfillment system decomposed into multiple independant components (e.g. microservices). Showing concrete implementation alternatives using e.g. Java, Spring Boot, Apache Kafka, Camunda, Zeebe, ...
Java
1,221
star
2

camunda-7-springboot-amqp-microservice-cloud-example

Simple example using Camunda and Spring Boot to define a simple microservice communcating via AMQP, fully unit tested and deployable in the cloud
Java
215
star
3

camunda-csharp-showcase

Showcase using Camunda BPM on .NET Platform with C# (no Java Coding required!)
C#
165
star
4

flowing-trip-booking-saga-c-sharp

Example implementation of the Saga pattern for the classic trip booking example using the lightweight open source workflow engine (Camunda) and C#.
C#
164
star
5

flowing-retail-old

REPLACED BY MORE CURRENT VRSION OF THIS EXAMPLE: https://github.com/berndruecker/flowing-retail
Java
63
star
6

ticket-booking-camunda-8

A ticket booking example using Camunda Cloud, RabbitMQ, REST and two sample apps (Java Spring Boot and NodeJS)
Java
26
star
7

trip-booking-saga-serverless

Standard example of the Saga pattern (trip booking) in a serverless world
JavaScript
22
star
8

customer-onboarding-camunda-8-springboot

A simple onboarding process example using BPMN, Camunda Cloud, Java, Spring Boot and REST
Java
21
star
9

flowing-retail-concept-java

Simple application showing the concepts using plain Java without infrastructure
Java
20
star
10

camunda-csharp-client

Small (hacky!) client library wrapping around the Camunda REST API. Use to get started or demo - but note that this code is not supported or build for production!
C#
19
star
11

kafka-camunda-spring-simple

Simple Java Spring Boot example connecting to Confluent Cloud (Kafka) and Camunda Cloud (Zeebe)
Java
14
star
12

zeebe-camunda-dmn

Sample how to use Camunda DMN decisions in a Zeebe Workflow
Java
11
star
13

oreilly-training-process-automation

Labs for the OReilly Training "Process Automation in Modern Architectures"
11
star
14

customer-onboarding-camunda-8-springboot-extended

Example onboarding process using Camunda Cloud, Java, Spring Boot, REST and AMQP
Java
10
star
15

processautomationbook.com

Website for the book "Practical Process Automation" with O'Reilly
CSS
7
star
16

camunda-7-on-pcf

Tutorial how to run Camunda on Pivotal Cloud Foundary (PCF)
Java
6
star
17

flowing-retail-camunda-intro

Order flow implemented as one simple Camunda process application. Small sister of the flowing-retail example showing the same use case as system of collaborating microservices.
Java
6
star
18

camunda-7-remote-spring-boot-example

Example showing how to connect to a remote Camunda Run from Spring boot for external taks and OpenAPI REST calls
Java
6
star
19

kafka-connect-zeebe-benchmark

Python
5
star
20

bpmn-resilience-patterns

Showing how to leverage BPMN and/or the Camunda BPM engine to improve resilience by certain patterns around retrying and timeouts
Java
5
star
21

zeebe-loadtest-kubernetes

Load tests for Zeebe which can be run on Kubernetes using Helm charts to provision everything automatically
Java
5
star
22

camunda-zipkin-springboot-demo

POC using Spring Boot to show that you also trace whole workflows from Camunda with Zipkin.
Java
5
star
23

flowing-retail-payment-rest-spring-statemachine

Flowing Retail payment service implemented using Spring StateMachine (as comparison for Camunda)
Java
5
star
24

camunda-engine-7-harvester

Simple POC to show how to gather information about multiple Camunda engines across the enterprise
Java
4
star
25

customer-onboarding-camunda-7

Quick and dirty demo for an onboarding process from the book "Practical Process Automation" using Camunda Platform and Spring Boot
Java
4
star
26

camunda-7-openapi-demo

Java
3
star
27

zeebe-aws-event-bridge

summer hackdays 2020 project to prototype an integration between zeebe cloud and AWS EventBridge
Java
3
star
28

mule-camunda-24

Showcase using Mule and camunda BPM for a simple order process
Java
3
star
29

camunda-ready-to-receive-patterns

Some samples how to handle if a workflow instance in Camunda is not yet ready-to-receive a message
Java
2
star
30

advanced-workflow-patterns

JavaScript
1
star
31

zeebe-benchmark-demo

Simple local benchmark for smoketest of Zeebe performance
Java
1
star
32

camunda-compensation-examples

Java
1
star
33

custom-process-landscape

1
star
34

camunda-8-junit-tests-playgorund

Project to play with latest Camunda Cloud Zeebe testing libraries
Java
1
star
35

zeebe-first-contact

Hello World example used for first contact live demos
Java
1
star
36

camunda-interactive-lab

Interactive lab to do a plublic exercise to get Camunda running on participant machines, communicating with a central cloud Camunda instance to showcase some things - and to play around :-)
Java
1
star