在日常开发的过程中我们经常会需要调用第三方组件或者数据库,有的时候可能会因为网络抖动或者下游服务抖动,导致我们某次查询失败。
这种时候我们往往就会进行重试,当重试几次后依旧还是失败的话才会向上抛出异常进行失败。接下来阿粉就给大家演示一下通常是如何做的,以及如何更优雅的进行重试。
常规做法我们先来看一下常规做法,常规做法首先会设置一个重试次数,然后通过 while 循环的方式进行遍历,当循环次数没有达到重试次数的时候,直到有正确结果后就返回,如果重试依旧失败则会进行睡眠一段时间,再次重试,直到正常返回或者达到重试次数返回。
package com.example.demo.service;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Service
public class HelloService {
public String sayHello(String name) {
String result = "";
int retryTime = 3;
while (retryTime > 0) {
try {
//
result = name doSomething();
return result;
} catch (Exception e) {
System.out.println("send message failed. try again in 1's");
retryTime--;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
return result;
}
private int doSomething() {
Random random = new Random();
int i = random.nextInt(3);
System.out.println("i is " i);
return 10 / i;
}
}
这里为了模拟异常的情况,阿粉在 doSomething 函数里面进行了随机数的生成和使用,当随机出来的值为 0 的时候,则会触发 java.lang.ArithmeticException 异常,因为 0 不能作除数。
接下来我们再对外提供一个接口用于访问,代码如下
package com.example.demo.controller;
import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping(value = "/hello")
public String hello(@RequestParam("name") String name) {
return helloService.sayHello(name);
}
}
正常启动过后,我们通过浏览器进行访问。
可以看到,我们第一次方法的时候就成功的达到了我们要的效果,随机数就是 0 ,在 1 秒后重试后结果正常。在多试了几次过后,会遇到三次都是 0 的情况,这个时候才会抛出异常,说明服务是真的有问题了。