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.
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
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.