Choreography Saga Pattern with Spring Cloud Kafka

John Chang
3 min readJan 3, 2021

An order and payment microservices application has been made with Spring Webflux, Spring Cloud Stream and Kafka as it’s binder. The purpose of using Spring Cloud Stream is to be able to decouple the Messaging Queue used, e.g. later may switch to RabbitMQ or Solace. GitHub project is found here.

Problems with the Monolithic Architecture

Traditionally, the order-service would send a HTTP request to get the information about the user’s credit balance. The problem with this approach is the-service assumes that payment-service will run with no server issues. If the payment service faces network issues and what not, the failure will cascade back down to the order service. This leads to a strict coupling in system design which is what we want to avoid. The order service should not need to know about the payment service, and vice versa.

Choreography Saga Pattern
The saga pattern provides transaction management using a sequence of local transactions. These are atomic work efforts performed by a saga participant. Each local transaction updates the database and publishes an event to trigger the next local transaction in the saga. In this pattern, microservices publish events typically onto a Message Queue on a topic; then corresponding recipients subscribed to the topic would receive incoming events for further processing. Read more about it here: Microservices Saga Pattern

Architecture

Events

Events are either published or subscribed to and components have been created to resemble to this contract.

  • An EventHandler is a component which consumes an event and emits an event.
  • An EventConsumer is a component which solely consumes events it is subscribed to

Data Flow

  • The order-service is invoked to create a new order purchase.
  • This request is processed and raised as an OrderPurchaseEvent. This means that a new request has been made, whilst keeping the status as CREATED.
  • The payment service will be listening in the component OrderPurchaseEventHandler for this event and be responsible for the transaction for this event. If the balance was insufficient, a PaymentEvent with the status DECLINED will be sent, else APPROVED.
  • The PaymentEventHandler listens for this, persists the transaction and emits a TransactionEvent with status SUCCESSFUL or UNSUCCESSFUL
  • TransactionEventConsumer listens and if the Transaction status was SUCCESSFUL, the Order is then persisted in the database as COMPLETED else FAILED
  • After creating 3 separate orders with the userId of 1, the first two are completed but the third fails due to an insufficient balance.

All the source code instructions to setup Kafka and the microservices are in the README of the GitHub project. Feel free to play around and let me know how it goes!

--

--