Example
1. Handling Payment Processing Failures
In a microservices architecture, let’s assume we have an e-commerce platform with a Payment Service responsible for processing payments by communicating with a third-party payment gateway (e.g., Stripe, PayPal). Due to various reasons (e.g., network instability, gateway downtime, rate-limiting), payment processing may occasionally fail, but these failures are often transient.
The goal is to implement a retry mechanism with different retry policies, backoff strategies, and recovery handling, ensuring payment operations are retried when appropriate but without overloading the payment gateway.
Service: PaymentService calls a third-party payment API to process payments.
Retry Logic:
Retry on specific transient failures like
TimeoutExceptionandPaymentGatewayUnavailableException.Use an exponential backoff strategy to avoid overloading the payment gateway.
Limit the number of retry attempts to prevent excessive retries.
Fallback Recovery: After exhausting retries, the transaction is marked as pending, and the user is notified to try again later.
PaymentService.java class
package org.example.service;
import org.example.client.PaymentGatewayClient;
import org.example.exception.PaymentException;
import org.example.exception.PaymentGatewayUnavailableException;
import org.example.model.PaymentRequest;
import org.example.model.PaymentResponse;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeoutException;
@Service
public class PaymentService {
private final PaymentGatewayClient paymentGatewayClient;
public PaymentService(PaymentGatewayClient paymentGatewayClient) {
this.paymentGatewayClient = paymentGatewayClient;
}
// Retryable method for processing payment
@Retryable(
retryFor = { TimeoutException.class, PaymentGatewayUnavailableException.class },
maxAttempts = 5,
backoff = @Backoff(delay = 2000, multiplier = 2.0)
)
public PaymentResponse processPayment(PaymentRequest request) throws PaymentException {
// Call the third-party payment gateway
return paymentGatewayClient.processPayment(request);
}
// Recovery method if retries fail
@Recover
public PaymentResponse recover(PaymentGatewayUnavailableException e, PaymentRequest request) {
System.out.println("Recovering after retries failed for request: " + request.getTransactionId());
// Mark transaction as pending and notify user to retry
return markTransactionAsPending(request);
}
private PaymentResponse markTransactionAsPending(PaymentRequest request) {
// Logic to mark the transaction as pending due to payment failures
return new PaymentResponse("PENDING", "Your payment is pending. Please try again later.");
}
}PaymentGatewayClient.java class
PaymentException and PaymentGatewayUnavailableException java class
PaymentRequest and PaymentResponse java Class
Last updated