Skip to content

Java framework for simplifying the implementations of sagas in Spring Boot applications.

License

Notifications You must be signed in to change notification settings

kirksc1/sagacious

Repository files navigation

Sagacious

Build Status codecov

Purpose

Sagacious is an effort to provide a framework for implementing the saga design pattern in a non-invasive manner. Its primary focus is on simplifying the orchestration style of sagas.
Although usable in any spring-enabled service, its designed for use within Spring Boot applications.

Setup

Sagacious uses 2 database entities and its default implementation uses JPA. The entities (Saga and Participant) have the following table structures within an RDBMS.

Saga

CREATE TABLE saga (
    identifier VARCHAR(255) NOT NULL, 
    completed BOOLEAN NOT NULL, 
    failed BOOLEAN NOT NULL, 
    PRIMARY KEY (identifier)
)

Participant

CREATE TABLE participant (
    identifier VARCHAR(255) NOT NULL, 
    action_definition VARCHAR(4000) NOT NULL, -- or CLOB as needed
    fail_completed BOOLEAN, 
    order_index INTEGER NOT NULL, 
    saga_id VARCHAR(255) NOT NULL, 
    PRIMARY KEY (identifier)
)

Usage

Saga Initiation

Establish a saga to which participants can be added on an as needed basis. Participants registered within the execution of the method will be added to the saga. Successful completion of the method results in a completed saga. Exceptions initiate the compensating actions associated with each participant.

@RequestMapping(path = "/orders", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.CREATED)
@SagaOrchestrated
public String createOrder(@RequestBody OrderResource orderResource) throws Exception {
    //clever business logic
}

Reference: OrderController.java

NOTE: @SagaOrchestrated may also be customized.

Participant Registration

Register a saga participant, and its compensating action, with the current saga, if present. The method's parameter or return value may be provided to a factory bean (named paymentActionDefinitionFactory below) method that creates a definition for the compensating action.

Annotating a parameter with @ParticipantData indicates it should be passed to the factory as input.

@SagaParticipant(actionDefinitionFactory="paymentActionDefinitionFactory")
public String initiatePayment(@ParticipantData String paymentDeviceId, Float amount) throws FailedPaymentException {
    //more clever business logic
}

If no parameter is annotated with @ParticipantData, then the method's return value will be passed to the factory as input.

@SagaParticipant(actionDefinitionFactory="paymentActionDefinitionFactory")
public String initiatePayment(String paymentDeviceId, Float amount) throws FailedPaymentException {
    //more clever business logic
}

Reference: PaymentServiceClient.java

NOTE: @SagaParticipant may also be customized.

Saga State

Sagas have two key statuses that influence its behavior.

  • Completed: Indicates that all known processing is complete on the Saga. This processing could apply to either successful processing or processing of compensating actions upon a Saga failure.
  • Failed: Indicates that a Saga has failed.

The default SagaManager implementation is the SimpleSagaManager

Compensating Actions

Within a saga, each step has a compensating action that, upon saga failure, should effectively undo the step. For example, a step that authorized payment for an order might have a compensating action that reversed the authorization. The compensating action need not return the entire system back to the pre-saga state. It only needs to return it to effectively the same state. Each system may have its own view of what "effectively" means in its context.

Sagacious uses a CompensatingActionDefinition to define the details of the action that needs to be executed for a step should a saga failure occur. These definitions are executed by CompensatingActionExecutors. These executors may take many forms that communicate over various channels (i.e. REST, JMS). Each executor describes the definition(s) that it can execute through the use of the Executable annotation.

@Executable(scheme="http")
@Executable(scheme="https")
public class RestTemplateExecutor implements CompensatingActionExecutor {
    // implementation
}

CompensatingActionExecutor beans are checked in order (according to Spring's Ordered). The first bean that can execute the definition is passed the definition for execution.

Sagacious supports the following executors:

Sagacious Server Configurations

Sagacious provides server configurations through the use of the following server annotations:

  • @EnableParticipantServer : Enable limited interactions to support remote participants. The primary use case for this functionality is to support applications orchestrating sagas whose participants are orchestrating their own sagas, enabling a single saga to cover all participants.

About

Java framework for simplifying the implementations of sagas in Spring Boot applications.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published