Pular para o conteúdo principal

Tipos de Steps

O Sagaweaw infere automaticamente o tipo de cada step baseado na sua definição. Existem três tipos:


COMPENSABLE

Um step COMPENSABLE possui um método compensate() definido. Se um step posterior falhar, o Sagaweaw executará a compensação automaticamente.

.step("block-balance")
.invoke(this::blockBalance)
.compensate(this::unblockBalance) // ← Define compensação

Características

AspectoComportamento
CompensaçãoExecutada em ordem inversa
DadosContexto disponível para compensar
RetryConfigurável

Exemplo Completo

// Invoke: Bloqueia o saldo
private PixContext blockBalance(PixContext ctx) {
String blockId = balanceService.block(ctx.payerId(), ctx.amount());
return ctx.withBlockId(blockId); // Salva o ID para compensação
}

// Compensate: Desbloqueia usando o blockId salvo
private void unblockBalance(PixContext ctx) {
balanceService.unblock(ctx.blockId()); // Usa o ID salvo
}
Dica

Sempre salve no contexto os dados necessários para compensar (IDs, tokens, etc).


PIVOT

Um step PIVOT é o "ponto de não retorno". Não possui compensação definida. Após a execução bem-sucedida de um PIVOT, os steps anteriores não serão compensados mesmo se steps posteriores falharem.

.step("transmit-to-bacen")
.invoke(this::transmitToBacen)
// Sem .compensate() = PIVOT

Características

AspectoComportamento
CompensaçãoNão existe
Ponto de não retornoSim
RetryGeralmente configurado

Quando Usar

  • Operações irreversíveis: Envio de email, SMS, notificação push
  • Integrações externas sem rollback: APIs de terceiros, BACEN, gateways
  • Confirmações finais: Commit de transação externa

Exemplo

.step("transmit-to-bacen") // PIVOT
.invoke(this::transmitToBacen)
.retry(exponential(3, Duration.ofSeconds(1))) // Retry antes de desistir
Atenção

Se um PIVOT falhar após todas as tentativas de retry, a saga entra em estado FAILED e os steps COMPENSABLE anteriores são compensados.


RETRIABLE

Um step RETRIABLE tem retry infinito e não possui compensação. Ele deve sempre eventualmente ter sucesso. Use para operações idempotentes que podem falhar temporariamente.

.step("send-notification")
.invoke(this::sendNotification)
.retry(infinite()) // ← Retry infinito sem compensate = RETRIABLE

Características

AspectoComportamento
CompensaçãoNão existe
RetryInfinito
ExpectativaSempre terá sucesso

Quando Usar

  • Notificações: Email, SMS, push (idempotentes)
  • Atualizações de cache: Eventual consistency
  • Webhooks: Notificar sistemas externos

Exemplo

.step("send-confirmation-email")
.invoke(this::sendConfirmationEmail)
.retry(infinite(Duration.ofMinutes(5), Duration.ofHours(1))) // Min 5min, max 1h entre tentativas
Cuidado

Só use RETRIABLE se a operação for idempotente (executar várias vezes produz o mesmo resultado).


Tabela Comparativa

Tipocompensate()retry()Quando Usar
COMPENSABLE DefinidoOpcionalOperações reversíveis
PIVOT Não temRecomendadoPonto de não retorno
RETRIABLE Não teminfinite()Deve sempre ter sucesso

Fluxo de Inferência

O Sagaweaw determina o tipo automaticamente:

┌─────────────────────────────────────────┐
│ Step definido │
└─────────────────┬───────────────────────┘


┌─────────────────┐
│ Tem compensate? │
└────────┬────────┘

┌───────┴───────┐
│ │
SIM NÃO
│ │
▼ ▼
COMPENSABLE ┌─────────────────┐
│ Retry infinito? │
└────────┬────────┘

┌───────┴───────┐
│ │
SIM NÃO
│ │
▼ ▼
RETRIABLE PIVOT

Próximos Passos