Evento Framework
  • Introduction
  • Architecture Overview
    • Distributed Systems & Microservices
    • Recative Manifesto & Reactive Principles
    • State-of-the-art Patterns
      • DDD (Domain Driven Design)
      • CQRS (Command Query Responsability Separation)
      • Event Sourcing
      • Messaging
      • Saga
  • GETTING STARTED
    • Quick Start
    • TodoList - RECQ Tutorial
      • Problem Description and Requirement Gathering
      • RECQ Payload Design
      • RECQ Components Design
      • Set up your Development Environment
      • RECQ Payload Evento Implementation
        • Domain Commands
        • Domain Events
        • Views
        • Queries
      • RECQ Components Evento Implementation with Spring Data
        • TodoListAggregate
        • TodoList Model with Spring Data
        • TodoListProjector
        • TodoListProjection
        • TodoList Invoker
      • Expose the RECQ architecture with Spring Web
      • Test Your App
    • Extend TodoList - Handle Complexity Tutorial
      • Unique identifier generation
      • Extends behaviors with Observer and Services
      • Cross Domain Consistency with Sagas
      • Handle Real time data updates with MQTT and Save-Notify Pattern
  • RECQ Patterns
    • RECQ Patterns
    • RECQ System Pattern
      • Component
      • Message Gateway
      • System State Store
    • RECQ Communication Pattern
      • Component to Component
      • Component to System State Store
      • System State Store to Component
    • RECQ Component Pattern
      • Aggregate
      • Projector
      • Projection
      • Service
      • Invoker
      • Saga
      • Observer
  • Evento Framework
    • Evento Framework Introcution
    • Payload and Messages
      • Command
        • Domain Command
        • Service Command
      • Event
        • Domain and Service Event
      • Query and View
    • @Component
      • @Aggregate
        • Aggregate State
        • @AggregateCommandHandler
        • @EventSourcingHandler
      • @Projector
        • Projector @EventHandler
      • @Projection
        • @QueryHandler
      • @Service
        • @CommandHandler
      • @Invoker
      • @Saga
        • SagaState
        • @SagaEventHandler
      • @Observer
    • Dead Event Queues
    • EventoBundle
      • EventoServerMessageBusConfiguration
      • ConsumerStateStore
        • InMemoryConsumerStateStore
        • PostgresConsumerStateStore
        • MysqlConsumerStateStore
      • Context
      • TracingAgend and @Track
        • SentryTracingAgent
      • Autoscaling Protocol
        • ThreadCountAutoscalingProtocol
      • Injector and @Component
  • Evento Server
    • Evento Server Introduction
    • SetUp Evento Server
      • Advanced Options
      • Evento Event Store Modes: APES and CPES
    • Evento Server Cluster
    • Bundle Deploy Script
  • EVENTO GUI
    • Explore RECQ Systems Visually
    • GUI Auth
    • Payload Catalog
    • Component Catalog
    • Bundle Catalog
    • Cluster Status (Experimental)
    • Flows
      • Performance Evaluation
    • Application Graph
    • System State Store
  • Evento CLI
    • Evento CLI Introduction
    • Update Version
    • Publish
Powered by GitBook
On this page
  1. Evento Framework
  2. @Component

@Saga

Orchestrating Long-Running Transactions

The RECQ architecture emphasizes handling complex workflows that might span multiple services and data sources. In this context, the @Saga annotation plays a vital role in defining classes that coordinate these long-running transactions.

Understanding @Saga

The @Saga annotation marks a class within your Evento application as a saga. Sagas are stateful components responsible for managing the flow of a complex business process that involves multiple events. They ensure data consistency across these events and potentially interact with various services or projections.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface Saga {
    /**
     * Returns the version of the method.
     *
     * @return the version of the method
     */
    int version();
}

Here's a breakdown of the annotation's definition:

  • @Retention(RetentionPolicy.RUNTIME): Ensures the annotation information is retained at runtime, allowing Evento to identify saga classes.

  • @Target(ElementType.TYPE): Specifies that the annotation can only be applied to class declarations.

  • @Component: Inherits from the @Component annotation, indicating that the annotated class is a component within the Evento framework.

  • version (Attribute): Defines the version of the saga logic. Versioning helps manage changes to the saga's behavior over time.

Sagas in the RECQ Pattern

The RECQ pattern promotes modularity and separation of concerns. Sagas bridge the gap between domain events and actions that require coordination across services. They provide a way to manage complex workflows that cannot be easily handled by individual services.

Here are some key characteristics of sagas:

  • Long-Running Transactions: Sagas manage workflows that might span multiple events over time.

  • State Management: They maintain their own state to track the progress of the workflow.

  • Event-Driven: Sagas react to domain events emitted within the system.

  • Coordinating Actions: They might interact with various services, projections, or send commands to trigger actions based on the workflow logic.

The DemoSaga Example

@Saga(version = 1)
public class DemoSaga {

    @SagaEventHandler(init = true, associationProperty = "demoId")
    public DemoSagaState on(DemoCreatedEvent event,
                      CommandGateway commandGateway,
                      QueryGateway queryGateway,
                      EventMessage<?> message) {
       Utils.logMethodFlow(this, "on", event, "BEGIN");
       DemoSagaState demoSagaState = new DemoSagaState();
       demoSagaState.setAssociation("demoId", event.getDemoId());
       demoSagaState.setLastValue(event.getValue());
       Utils.logMethodFlow(this, "on", event, "END");
       return demoSagaState;
    }

    @SagaEventHandler(associationProperty = "demoId")
    public DemoSagaState on(DemoUpdatedEvent event,
                      DemoSagaState demoSagaState,
                      CommandGateway commandGateway,
                      QueryGateway queryGateway,
                      EventMessage<?> message) throws ExecutionException, InterruptedException {
       Utils.logMethodFlow(this, "on", event, "BEGIN");
       if (event.getValue() == 12)
       {
          var demo = queryGateway.query(new DemoRichViewFindByIdQuery(event.getDemoId())).get();
          System.out.println(jump(commandGateway, demo.getData().toString()));
       }
       demoSagaState.setLastValue(event.getValue());
       Utils.logMethodFlow(this, "on", event, "END");
       return demoSagaState;
    }

    @SagaEventHandler(associationProperty = "demoId")
    public DemoSagaState on(DemoDeletedEvent event,
                      DemoSagaState demoSagaState,
                      CommandGateway commandGateway,
                      QueryGateway queryGateway,
                      EventMessage<?> message) throws ExecutionException, InterruptedException {
       Utils.logMethodFlow(this, "on", event, "BEGIN");
       System.out.println(this.getClass() + " - on(DemoDeletedEvent)");
       var demo = queryGateway.query(new DemoRichViewFindByIdQuery(event.getDemoId())).get();
       var resp = commandGateway.send(new NotificationSendSilentCommand("lol" + demo.getData().toString())).get();
       System.out.println(resp);
       demoSagaState.setEnded(true);
       Utils.logMethodFlow(this, "on", event, "END");
       return demoSagaState;
    }

    public NotificationSentEvent jump(CommandGateway commandGateway, String msg) {
       return sendNotification(commandGateway, msg);
    }

    public NotificationSentEvent sendNotification(CommandGateway commandGateway, String msg) {
       return commandGateway.sendAndWait(new NotificationSendCommand(msg));
    }


}

The provided code snippet showcases a DemoSaga class:

  • It's annotated with @Saga(version = 1), indicating it's a saga with version 1.

  • It defines state management logic (covered in the next chapter) and several @SagaEventHandler methods:

    • The on method for DemoCreatedEvent initializes the saga state.

    • The on method for DemoUpdatedEvent updates the saga state and performs conditional logic based on the updated value.

    • The on method for DemoDeletedEvent performs actions upon deletion, including sending a notification and marking the saga as ended.

  • These methods demonstrate how sagas react to domain events and manage the workflow accordingly.

Key Takeaways

  • @Saga helps define classes that coordinate long-running transactions within your Evento application.

  • Sagas manage state, react to domain events, and potentially interact with services or projections to fulfill complex business processes.

  • Understanding @Saga is crucial for building robust workflows that span multiple events and actions within the RECQ architecture.

The next chapter will delve deeper into Saga State management, an essential aspect of working with sagas in Evento.

Previous@InvokerNextSagaState

Last updated 12 months ago