Pular para o conteúdo principal

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árioO que salvar
PagamentopaymentIntentId, chargeId
Reserva de estoquereservationId
Bloqueio de saldoblockId
Validação de tokenvalidationToken
AgendamentoscheduleId

Boas Práticas

Faça

  • Salve apenas IDs e tokens
  • Use tipos primitivos (String, Long)
  • Nomeie claramente (ex: paymentIntentId, não id)

Evite

  • Salvar objetos complexos inteiros
  • Depender de estado externo
  • Assumir que o output existe (valide!)

Relacionados