Careeroza
Real World Example
Surviving a Payment Provider Outage
UPI and card providers in India sometimes have partial outages during peak hours. Payment platforms (Razorpay, PhonePe, Paytm) and the shops using them protect themselves so that checkout fails gracefully, and the rest of the app (search, product pages, cart) keeps working. Netflix popularised these patterns with Hystrix; Resilience4j is the modern Java version.
user clicks Pay
-> order-service.charge()
Bulkhead(max 10 concurrent) -- full? -> "payment pending"
CircuitBreaker(paymentService) -- open? -> "payment pending"
Retry(2x on timeout, same Idempotency-Key)
-> payment-service -> bank / UPI provider
meanwhile: search, product pages, cart -> unaffected (other threads, other breakers)ShopEase Payment Call
@Service
@RequiredArgsConstructor
@Slf4j
public class PaymentGateway {
private final PaymentClient paymentClient;
private final OrderRepository orders;
@Retry(name = "paymentService")
@CircuitBreaker(name = "paymentService", fallbackMethod = "markPending")
@Bulkhead(name = "paymentService")
public PaymentResult charge(Order order) {
PaymentResponse res = paymentClient.charge(
"order-" + order.getId(), // same key on every retry
new ChargeRequest(order.getId(), order.getTotal(), order.getPaymentMode()));
return PaymentResult.paid(res.paymentId());
}
PaymentResult markPending(Order order, Throwable ex) {
log.warn("Payment for order {} pending: {}", order.getId(), ex.getClass().getSimpleName());
order.markPaymentPending();
orders.save(order);
return PaymentResult.pending(); // a scheduled job / webhook confirms later
}
}Example
During the outage the user gets a clear answer in milliseconds instead of a 30-second hang:
curl -X POST localhost:8080/api/orders -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"userId": 42, "productId": 7, "quantity": 1, "paymentMode": "UPI"}'Example output
HTTP/1.1 202 Accepted
{"orderId":1007,"status":"PAYMENT_PENDING","message":"We are confirming your payment. You will get an SMS in a few minutes."}
$ curl -s localhost:8082/actuator/health | jq .components.circuitBreakers
{"status":"UNKNOWN","details":{"paymentService":{"status":"CIRCUIT_OPEN",
"details":{"failureRate":"70.0%","state":"OPEN","notPermittedCalls":42}}}}Tip: Alert on circuit breaker state changes (Prometheus metric resilience4j_circuitbreaker_state). An OPEN circuit is a page for the on-call engineer, not something to discover from angry tweets.