Pular para o conteúdo principal

SagaDefinition

A interface base que toda saga deve implementar.


Definição

public interface SagaDefinition<C> {

/**
* Define os steps da saga usando o builder.
*
* @param builder O builder fluent para configurar os steps
*/
void define(SagaBuilder<C> builder);
}

Parâmetros de Tipo

ParâmetroDescrição
CTipo do contexto da saga (deve ser serializável para JSONB)

Exemplo de Implementação

@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());
}
}

️ Anotação @Saga

A anotação @Saga registra a definição no container Spring:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Saga {

/**
* Nome único da saga usado para identificação e disparo.
*/
String value();

/**
* Descrição opcional para documentação.
*/
String description() default "";
}

Atributos

AtributoTipoObrigatórioDescrição
valueStringNome único da saga
descriptionStringDescrição opcional para documentação

Exemplo

@Saga(
value = "pix-payment",
description = "Processa pagamentos PIX com compensação automática"
)
public class PixPaymentSaga implements SagaDefinition<PixContext> {
// ...
}

Regras Importantes

Não use @Transactional

@Saga("pix-payment")
@Transactional // <DocIcon name="alert" /> ERRADO! O engine gerencia as transações
public class PixPaymentSaga implements SagaDefinition<PixContext> {
// ...
}

O Sagaweaw gerencia todas as transações internamente. Usar @Transactional pode causar comportamento inesperado.


Injeção de Dependências

O Sagaweaw é compatível com injeção de dependências do Spring:

@Saga("order-processing")
public class OrderProcessingSaga implements SagaDefinition<OrderContext> {

private final StockService stockService;
private final PaymentService paymentService;

// Injeção via construtor (recomendado)
public OrderProcessingSaga(
StockService stockService,
PaymentService paymentService
) {
this.stockService = stockService;
this.paymentService = paymentService;
}

@Override
public void define(SagaBuilder<OrderContext> builder) {
// ...
}
}

Relacionados