Ciclo de Vida
Cada saga passa por estados bem definidos durante sua execução. Isso garante rastreabilidade completa e recuperação previsível.
Estados da Saga
┌─────────┐
│ STARTED │
└────┬────┘
│
▼
┌───────────┐
│ EXECUTING │◄──────────────────┐
└─────┬─────┘ │
│ │
┌─────────────┴─────────────┐ (retry)
│ │ │
(sucesso) (falha) │
│ │ │
▼ ▼ │
┌───────────┐ ┌─────────────┐ │
│ COMPLETED │ │ COMPENSATING│─────┘
└───────────┘ └──────┬──────┘
│
┌───────────── ─┴──────────────┐
│ │
(sucesso) (falha)
│ │
▼ ▼
┌─────────────┐ ┌────────┐
│ COMPENSATED │ │ FAILED │
└─────────────┘ └────────┘
Descrição dos Estados
STARTED
Estado inicial quando a saga é criada.
SagaExecution execution = sagaManager.start(PixPaymentSaga.class, context);
// execution.sagaId() retorna o UUID gerado para acompanhamento
| Aspecto | Valor |
|---|---|
| Duração | Milissegundos |
| Próximo | EXECUTING |
| Trigger | sagaManager.start() |
EXECUTING
A saga está processando os steps sequencialmente.
EXECUTING: step 1 de 4 - validate-dict ●
| Aspecto | Valor |
|---|---|
| Duração | Variável |
| Próximo | COMPLETED ou COMPENSATING |
| Trigger | Início do primeiro step |
COMPLETED
Todos os steps foram executados com sucesso. Estado final positivo.
COMPLETED ✓ - 4/4 steps executados em 2.3s
| Aspecto | Valor |
|---|---|
| Duração | Final |
| Próximo | - |
| Trigger | Último step concluído |
COMPENSATING
Um step falhou e as compensações estão sendo executadas em ordem inversa.
COMPENSATING: rollback step 2 de 3 - block-balance ↩️
| Aspecto | Valor |
|---|---|
| Duração | Variável |
| Próximo | COMPENSATED ou FAILED |
| Trigger | Falha em step após retries |
COMPENSATED
Todas as compensações foram executadas com sucesso. A saga foi revertida.
COMPENSATED ↩️ - 3 compensações executadas em 0.8s
| Aspecto | Valor |
|---|---|
| Duração | Final |
| Próximo | - |
| Trigger | Última compensação concluída |
FAILED
Estado terminal de falha. Ocorre quando:
- Um PIVOT falha após todas as tentativas de retry
- Uma compensação falha (saga vai para Dead Letter)
FAILED ✗ - transmit-to-bacen: timeout após 3 tentativas
| Aspecto | Valor |
|---|---|
| Duração | Final |
| Próximo | Manual (Dead Letter) |
| Trigger | Falha irrecuperável |
Transições de Estado
Cenário: Sucesso Completo
STARTED → EXECUTING → COMPLETED
│ │ │
│ │ └─ Fim
│ └─ Steps 1, 2, 3, 4 ✓
└─ Início
Cenário: Falha com Compensação
STARTED → EXECUTING → COMPENSATING → COMPENSATED
│ │ │ │
│ │ │ └─ Fim (rollback OK)
│ │ └─ comp 2, comp 1 ↩️
│ └─ step 1 ✓, step 2 ✓, step 3 ✗
└─ Início
Cenário: Falha em PIVOT
STARTED → EXECUTING → COMPENSATING → FAILED
│ │ │ │
│ │ │ └─ Dead Letter
│ │ └─ comp 2 ✓, comp 1 ✗
│ └─ step 1 ✓, step 2 ✓, step 3 (PIVOT) ✗
└─ Início
Consulta de Estado
Por ID (Java)
// Via Observability API: GET /api/sagas/{sagaId}
// Via SagaEngine (injeção direta):
Optional<SagaInstance> instance = engine.findById(sagaId);
instance.ifPresent(i -> {
System.out.println("Status: " + i.status());
System.out.println("Steps: " + i.steps().size());
});
Via REST API
# Sagas com falha
GET /api/sagas?status=FAILED
# Saga específica
GET /api/sagas/{id}
# Métricas agregadas
GET /api/sagas/metrics
dica
A Observability API fornece filtros por status, nome, data e chave de idempotência. Veja Observability API →.
Eventos de Ciclo de Vida
O Sagaweaw emite eventos para cada transição:
@Component
public class SagaEventListener {
@EventListener
public void onSagaStarted(SagaStartedEvent event) {
log.info("Saga {} started", event.getSagaId());
}
@EventListener
public void onSagaCompleted(SagaCompletedEvent event) {
log.info("Saga {} completed in {}ms",
event.getSagaId(),
event.getDuration());
}
@EventListener
public void onSagaFailed(SagaFailedEvent event) {
log.error("Saga {} failed: {}",
event.getSagaId(),
event.getError());
}
}