StepOutput
Padrão para capturar dados de um step para uso em compensações.
Conceito
StepOutput é um padrão para salvar IDs, tokens ou qualquer dado necessário para reverter uma operação. Esses dados são armazenados no contexto.
Exemplo
Problema
private OrderContext processPayment(OrderContext ctx) {
// Stripe retorna um ID de pagamento
PaymentIntent intent = stripe.createPaymentIntent(ctx.totalAmount());
// <DocIcon name="brain" /> Onde salvar o intent.id para usar na compensação?
}
Solução
private OrderContext processPayment(OrderContext ctx) {
PaymentIntent intent = stripe.createPaymentIntent(ctx.totalAmount());
// <DocIcon name="check" /> Salva no contexto para a compensação
return ctx.withPaymentIntentId(intent.getId());
}
private void refundPayment(OrderContext ctx) {
// <DocIcon name="check" /> Usa o ID salvo
stripe.refund(ctx.paymentIntentId());
}
Padrão Estruturado
Para sagas complexas, você pode usar uma estrutura dedicada:
public record OrderContext(
// Dados de entrada
String orderId,
BigDecimal amount,
// Step outputs organizados
StepOutputs outputs
) {
public OrderContext withOutput(String key, String value) {
return new OrderContext(orderId, amount, outputs.with(key, value));
}
}
public record StepOutputs(Map<String, String> data) {
public static StepOutputs empty() {
return new StepOutputs(Map.of());
}
public StepOutputs with(String key, String value) {
var newData = new HashMap<>(data);
newData.put(key, value);
return new StepOutputs(Map.copyOf(newData));
}
public String get(String key) {
return data.get(key);
}
}
Uso
private OrderContext processPayment(OrderContext ctx) {
PaymentIntent intent = stripe.createPaymentIntent(ctx.amount());
return ctx.withOutput("paymentIntentId", intent.getId());
}
private void refundPayment(OrderContext ctx) {
String intentId = ctx.outputs().get("paymentIntentId");
stripe.refund(intentId);
}
Quando Usar
| Cenário | O que salvar |
|---|---|
| Pagamento | paymentIntentId, chargeId |
| Reserva de estoque | reservationId |
| Bloqueio de saldo | blockId |
| Validação de token | validationToken |
| Agendamento | scheduleId |
Boas Práticas
Faça
- Salve apenas IDs e tokens
- Use tipos primitivos (String, Long)
- Nomeie claramente (ex:
paymentIntentId, nãoid)
Evite
- Salvar objetos complexos inteiros
- Depender de estado externo
- Assumir que o output existe (valide!)