架构设计中的重试机制

87 阅读2分钟

1. 背景

有时候我们对接第三方或者各个微服务之间服务调用有可能由于网络波动导致调用失败,这个时候我们需要重试机制

2. 示例

2.1. 循环重试

int retryTimes = 3;  
for(int i = 0; i < retryTimes; i++){  
    try{  
        // 请求接口的代码  
        break;  
    }catch(Exception e){  
        // 处理异常  
        Thread.sleep(1000); // 延迟1秒后重试  
    }  
}

2.2 使用递归结构

public void requestWithRetry(int retryTimes){  
    if(retryTimes <= 0) return;  
    try{  
        // 请求接口的代码  
    }catch(Exception e){  
        // 处理异常  
        Thread.sleep(1000); // 延迟1秒后重试  
        requestWithRetry(retryTimes - 1);  
    }  
}

2.3 消息队列重试

@Component  
@RocketMQMessageListener(topic = "myTopic", consumerGroup = "myConsumerGroup")  
public class MyConsumer implements RocketMQListener<String> {  
  
    @Override  
    public void onMessage(String message) {  
        try {  
            // 请求接口的代码  
        } catch (Exception e) {  
            // 处理异常  
            DefaultMQProducer producer = new DefaultMQProducer("myProducerGroup");  
            producer.setNamesrvAddr("127.0.0.1:9876");  
            try {  
                producer.start();  
                Message msg = new Message("myTopic""myTag", message.getBytes());  
                producer.send(msg);  
            } catch (Exception ex) {  
                // 处理发送异常  
            } finally {  
                producer.shutdown();  
            }  
        }  
    }  
}

2.4 自定义重试组件

代码我放在我的test_maven 仓库了

public class RetryUtils<R> {
    //重试等待时间长度
    private long retryTimesLong = 500L;
    //重试次数
    private int retryTimes = 3;
    // 返回结果
    private R result;
    // 需要重试的业务逻辑
    private Supplier<R> supplier;

    // 重试业务入口处
    public static <T> RetryUtils <T> fromTask(Supplier<T> supplier) {
        // 重试任务实力定义
        RetryUtils<T> retryUtil = new RetryUtils<>();
        retryUtil.setSupplier(supplier);
        return retryUtil;
    }

    public RetryUtils<R> setSupplier(Supplier<R> supplier) {
        this.supplier = supplier;
        return this;
    }

    public RetryUtils<R> retryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
        return this;
    }

    public RetryUtils<R> retryTimesLong(long retryTimesLong) {
        this.retryTimesLong = retryTimesLong;
        return this;
    }

    // 重试业务逻辑
    public Optional<R> getResult() {
        int curRetryTime = 1;
        // 辅助判断是否重试成功
        boolean retryIsSuccess = Boolean.FALSE;
        while (curRetryTime < retryTimes + 1) {
            try {
                //执行逻辑
                result = this.supplier.get();
                curRetryTime ++;
                retryIsSuccess = Boolean.TRUE;
            } catch (Exception e) {
                if ((!retryIsSuccess) && curRetryTime < this.retryTimes) {
                    // 进行下一轮重试
                    try {
                        Thread.sleep(this.retryTimesLong);
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                    continue;
                }
                // 异常且无需重试
                throw new RuntimeException(e);
            }
            // 检查是否运行成功
            if (retryIsSuccess) {
                // 运行成功,返回结果
                return (Optional<R>) Optional.ofNullable(result);
            }
        }
        // 运行到这里说明一次都没有成功
        return Optional.empty();
    }


    public static void main(String[] args) {

        Optional<Boolean> result = RetryUtils.<Boolean>fromTask(() -> {
                    return task();})
                .retryTimes(3)
                .retryTimesLong(500L)
                .getResult();

        Optional<Boolean> result1 = RetryUtils.<Boolean>fromTask(() -> {
                    return task();})
                .retryTimes(3)
                .retryTimesLong(500L)
                .getResult();

    }
    public static Boolean task(){
        System.out.println("测试");
        return Boolean.TRUE;
    }
}