guava-retrying3 学习

2023-07-02  本文已影响0人  月巴大叔

使用场景

做自动化场景,对于一些数据统计,有时数据同步更新会遇到延迟的场景,延时的时间可能不确定,此时,如果用 sleep 一定时间的话,可能会造成时间的浪费。那么有什么方法了避免呢,比如使用重试机制,设置重试的时间和重试的次数,当获取不到数据时根据预定的时间来重新请求接口。

重试的实现的要素

guava-retrying 策略介绍

构造一个 Retryer

Retryer<T> retryer = RetryerBuilder.<T>newBuilder()
                .retryIfException()
                // 自定义重试条件
                .retryIfExceptionOfType(NeedRetryException.class)
                //停止策略,最大尝试请求, attemptNumber次
                .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNumber))
                //等待策略,每次请求间隔1s
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                //尝试请求时间限制,不能超过 taskTime
                .withAttemptTimeLimiter(new FixedAttemptTimeLimit(taskTime, TimeUnit.SECONDS, Executors.newCachedThreadPool()))
                //方法用于配置阻塞策略,指定在进行重试时的阻塞行为
                .withBlockStrategy(spinBlockStrategy)
                //重试过程的监听策略,打印了尝试的次数
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.info("尝试次数 " + attempt.getAttemptNumber());
                    }
                })
                .build();

尝试定义一个方法,使用 Callable 接口作为参数传入一个执行的任务

 public static <T> T retry(Callable<T> task, int attemptNumber, int sleepTime, int taskTime) throws Throwable {
        SpinBlockStrategy spinBlockStrategy = new SpinBlockStrategy();
        spinBlockStrategy.block(1);
        Retryer<T> retryer = RetryerBuilder.<T>newBuilder()
                .retryIfException()
                // 自定义重试条件
                .retryIfExceptionOfType(NeedRetryException.class)
                //停止策略,最大尝试请求, attemptNumber次
                .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNumber))
                //等待策略,每次请求间隔1s
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                //尝试请求时间限制,不能超过 taskTime
                .withAttemptTimeLimiter(new FixedAttemptTimeLimit(taskTime, TimeUnit.SECONDS, Executors.newCachedThreadPool()))
                //方法用于配置阻塞策略,指定在进行重试时的阻塞行为
                .withBlockStrategy(spinBlockStrategy)
                //重试过程的监听策略,打印了尝试的次数
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.info("尝试次数 " + attempt.getAttemptNumber());
                    }
                })
                .build();
        try {
            return retryer.call(task);
        } catch (RetryException | ExecutionException e) {
            //throw inner exception
            String msg = "";
            log.error("retry internal error: {}", msg);
            throw new RuntimeException(msg);
        }
    }

guava-retrying3 结合testng使用,如果当我们Assert来作为判断任务的尝试条件时,有一个点需要注意,retry中的 call 方法最终抛出的对象为 throw new ExecutionError((Error)cause),这边 new 出了一个 com.google.common.util.concurrent.ExecutionError 类的对象。而不是 java.util 类的。因此,我们需要重写重试报错类型


image.png

代码中call的方法

retryer.call(task)

 private void wrapAndThrowRuntimeExecutionExceptionOrError(Throwable cause) {
        if (cause instanceof Error) {
            throw new ExecutionError((Error)cause);
        } else {
            throw new UncheckedExecutionException(cause);
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读