SagaDefinition
The base interface that every saga must implement.
Definition
public interface SagaDefinition<C> {
/**
* Defines the saga steps using the builder.
*
* @param builder The fluent builder for configuring steps
*/
void define(SagaBuilder<C> builder);
}
Type Parameters
| Parameter | Description |
|---|---|
C | The saga context type (must be serializable to JSONB) |
Implementation Example
@Saga("pix-payment")
public class PixPaymentSaga implements SagaDefinition<PixContext> {
private final DictService dictService;
private final BalanceService balanceService;
private final BacenService bacenService;
public PixPaymentSaga(
DictService dictService,
BalanceService balanceService,
BacenService bacenService
) {
this.dictService = dictService;
this.balanceService = balanceService;
this.bacenService = bacenService;
}
@Override
public void define(SagaBuilder<PixContext> builder) {
builder
.step("validate-dict")
.invoke(this::validateDict)
.compensate(this::invalidateDict)
.step("block-balance")
.invoke(this::blockBalance)
.compensate(this::unblockBalance)
.step("transmit-to-bacen")
.invoke(this::transmitToBacen)
.retry(exponential(3, Duration.ofSeconds(1)))
.build();
}
// --- Invoke Methods ---
private PixContext validateDict(PixContext ctx) {
String token = dictService.validate(ctx.dictKey());
return ctx.withValidationToken(token);
}
private PixContext blockBalance(PixContext ctx) {
String blockId = balanceService.block(ctx.payerId(), ctx.amount());
return ctx.withBlockId(blockId);
}
private PixContext transmitToBacen(PixContext ctx) {
bacenService.transmit(ctx.transactionId(), ctx.amount());
return ctx;
}
// --- Compensate Methods ---
private void invalidateDict(PixContext ctx) {
dictService.invalidate(ctx.validationToken());
}
private void unblockBalance(PixContext ctx) {
balanceService.unblock(ctx.blockId());
}
}
️ @Saga Annotation
The @Saga annotation registers the definition in the Spring container:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Saga {
/**
* Unique saga name used for identification and triggering.
*/
String value();
/**
* Optional description for documentation.
*/
String description() default "";
}
Attributes
| Attribute | Type | Required | Description |
|---|---|---|---|
value | String | Unique saga name | |
description | String | Optional description for documentation |
Example
@Saga(
value = "pix-payment",
description = "Processes PIX payments with automatic compensation"
)
public class PixPaymentSaga implements SagaDefinition<PixContext> {
// ...
}
Important Rules
Do Not Use @Transactional
@Saga("pix-payment")
@Transactional // <DocIcon name="alert" /> WRONG! The engine manages transactions
public class PixPaymentSaga implements SagaDefinition<PixContext> {
// ...
}
Sagaweaw manages all transactions internally. Using @Transactional can cause unexpected behavior.
Dependency Injection
Sagaweaw is compatible with Spring dependency injection:
@Saga("order-processing")
public class OrderProcessingSaga implements SagaDefinition<OrderContext> {
private final StockService stockService;
private final PaymentService paymentService;
// Constructor injection (recommended)
public OrderProcessingSaga(
StockService stockService,
PaymentService paymentService
) {
this.stockService = stockService;
this.paymentService = paymentService;
}
@Override
public void define(SagaBuilder<OrderContext> builder) {
// ...
}
}