Backend Development 7 min read

Implementing Retry Patterns in Microservices with Resilience4j

Learn how to design resilient microservices by implementing retry mechanisms using Resilience4j, including configuration, code examples for order and product services, handling exceptions, and testing the automatic retry behavior to improve system availability while noting limitations for non‑idempotent APIs.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Implementing Retry Patterns in Microservices with Resilience4j

Preface

Microservices are essentially distributed architecture; when using distributed systems any unpredictable issues (such as network, service, or middleware availability problems) can occur. Problems in one system may directly affect another, so system design must ensure its own resilience while avoiding cascading failures to downstream services.

Retry Mode

In a microservice architecture with multiple services (A, B, C, D), service A may depend on B, which depends on C, and so on. If service D fails to respond as expected—e.g., due to an OutOfMemoryError or Internal Server Error—this exception can affect downstream services and degrade user experience.

Similar to network communication exceptions, most cases can be resolved by refreshing the request. In production, service D is deployed with multiple instances behind a load balancer to achieve high availability. If one instance cannot respond, a retry can be routed by the load balancer to a healthy instance, ensuring application availability.

Example Program

Architecture Diagram

As shown, this simple diagram simulates an e‑commerce order flow.

用户登录浏览商品 (商品库存模块)

扣减商品库存 (商品库存模块)

创建商品订单 (订单模块)

product‑service calls order‑service to place an order.

Code Implementation

<code>├── retry-demo
   ├── order-service        #订单服务  (8070)
   └── product-service      #商品库存服务  (8050)
</code>

Dependency note: using resilience4j circuit breaker instead of the outdated Hystrix.

<code><dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.6.1</version>
</dependency>
</code>

Define retry policy for the interface.

<code>resilience4j.retry:
  instances:
    ratingService:
      maxRetryAttempts: 1 #重试策略
      retryExceptions:   #针对哪些异常进行重试
        - org.springframework.web.client.HttpServerErrorException
</code>

Consumer interface. product‑service (port 8050).

<code>/**
 * 用户点击购买
 */
@SneakyThrows
@GetMapping("/order")
public String buy() {
    // 模拟调用 订单服务下单
    orderService.createOrder().get();
    return "success";
}
</code>

Define remote‑call class wrapped with Retry.

<code>/**
 * 创建订单
 * name: 指定接口重试配置名称
 * fallbackMethod: 重试后降级方法
 */
@Bulkhead(name = "createOrder", fallbackMethod = "getError")
public CompletableFuture<String> createOrder() {
    return CompletableFuture.supplyAsync(() ->
        restTemplate.getForEntity("http://localhost:8070/createOrder", String.class).getBody()
    );
}

public CompletableFuture<String> getError(Throwable error) {
    log.warn("创建订单失败了 {}", error.getMessage());
    return CompletableFuture.completedFuture("");
}
</code>

Service provider. order‑service (port 8070).

<code>@RestController
public class PayController {
    private static int num = 0;
    @SneakyThrows
    @GetMapping("/createOrder")
    public String createOrder() {
        log.info("开始请求创建订单接口 {}", ++num);
        // 请求次数奇数模拟创建订单异常
        if (num % 2 != 0) {
            throw new RuntimeException();
        }
        return "创建订单服务";
    }
}
</code>

Start Testing

Request product service, returns success.

<code>curl http://localhost:8050/order
success
</code>

Order service logs show the first request triggers an exception, then the consumer automatically retries, producing a second call.

<code>2020-12-06 15:50:07.664  INFO 25846 --- [nio-8070-exec-1] c.e.o.controller.OrderController : 开始请求创建订单接口 1
2020-12-06 15:50:07.686  ERROR 25846 --- [nio-8070-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException] with root cause
... 异常日志 ...
2020-12-06 15:50:08.271  INFO 25846 --- [nio-8070-exec-2] c.e.o.controller.OrderController : 开始请求创建订单接口 2
</code>

Summary

Retry mode can automatically issue retries in code, avoiding manual refresh for end users, but it increases overall response time and is unsuitable for non‑idempotent interfaces.

Source code: https://github.com/lltx/microservices-pattern

Reference and some images: https://www.vinsguru.com

backenddistributed systemsMicroservicesSpring BootretryResilience4j
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.