JAVA重试器

google的guava-retrying

特点

支持设置重试次数和间隔时间,支持多种复杂场景的重试策略,延迟策略

而且支持多个异常或者自定义实体对象的重试源,让重试功能有更多的灵活性

线程安全,我们只需要关注我们的业务逻辑实现即可

内部使用线程池管理线程

基于命令模式使用链式调用,使用方便

pom

<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>

用法

// 重试条件
Predicate<String> condition = response -> Objects.nonNull(response) 
    && "处理中".equals(response.getReturnCode());

Optional<String> response = RetryUtil.retry(
                condition, // 重试条件
                () -> invoke(request), // 重试任务(比如调用接口)
                500, // 500ms重试一次, 可以做成配置化
                3);  // 一共重试3次, 可以做成配置化

return response.orElse(null);

RetryUtil是我对guava-retrying的封装实现,下面的代码大家可以直接拿去使用,只需要按照业务改下重试条件和重试任务以及重试间隔和次数即可:

/**
 * 根据输入的condition重复做task,在规定的次数内达到condition则返回,
 * 如果超过retryTimes则返回null, 重试次数,整个重试时间以及retry exception都会记录log
 *
 * @param condition  重试条件,比如接口返回errorCode为处理中,或不是最终需要的结果
 * @param task       重试做的任务
 * @param sleepTime  重试间隔时间,单位毫秒
 * @param retryTimes 重试次数
 * @return targetBean
 */
public static <V> Optional<V> retry(Predicate<V> condition, Callable<V> task, int sleepTime, int retryTimes) {
    Optional<V> result = Optional.empty();
    StopWatch stopWatch = new StopWatch();
    try {
        stopWatch.start();
        Retryer<V> retry = RetryerBuilder.<V>newBuilder()
                // 默认任务执行过程中发生异常自动重试
                .retryIfException()
                // 重试条件(按照业务场景)
                .retryIfResult(condition)
                // 等待策略
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.MILLISECONDS))
                // 重试策略
                .withStopStrategy(StopStrategies.stopAfterAttempt(retryTimes))
                // 重试监听器
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        // 记录重试次数和异常信息                        
                        log.info(MessageFormat.format("{0}th retry", attempt.getAttemptNumber()));
                        if (attempt.hasException()) {
                            log.error(MessageFormat.format("retry exception:{0}", attempt.getExceptionCause()));
                        }
                    }
                }).build();

        // 开始执行重试任务
        result = Optional.ofNullable(retry.call(task));
    } catch (Exception e) {
        log.error("retry fail:", e.getMessage());
    } finally {
        stopWatch.stop();
        log.info("retry execute time", stopWatch.getTime());
    }
    return result;
}

重试间隔时间和重试次数可以做成可配置的,方便后续根据日志记录观察调整

相关重试策略和api介绍

AttemptTimeLimiter:单次任务执行时间限制(如果单次任务执行超时,则终止执行当前任务)

BlockStrategies:任务阻塞策略,默认策略为:BlockStrategies.THREAD_SLEEP_STRATEGY,也就是调用Thread.sleep ()

StopStrategy:停止重试策略,提供三种:

StopAfterDelayStrategy:设定一个最长允许的执行时间,比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常RetryException

NeverStopStrategy:不停止,用于需要一直轮询直到返回期望结果的情况

    StopAfterAttemptStrategy:设定最大重试次数,如果超出最大重试次数则停止重试,并返回重试异常

WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长:

    FixedWaitStrategy:固定等待时长策略

    RandomWaitStrategy:随机等待时长策略

    IncrementingWaitStrategy:递增等待时长策略

    ExponentialWaitStrategy:指数等待时长策略

    FibonacciWaitStrategy:斐波那契等待时长策略

    ExceptionWaitStrategy:异常时长等待策略

    CompositeWaitStrategy:复合时长等待策略

spring的spring-retry

pom

		<dependency>
			<groupId>org.springframework.retry</groupId>
			<artifactId>spring-retry</artifactId>
		</dependency>

用法

package hello;

import org.springframework.remoting.RemoteAccessException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class RemoteService {
@Retryable(value= {RemoteAccessException.class},maxAttempts = 3,backoff = @Backoff(delay = 5000l,multiplier = 1))
public void call() throws Exception {
        System.out.println("do something...");
        throw new RemoteAccessException("RPC调用异常");
}
@Recover
public void recover(RemoteAccessException e) {
        System.out.println(e.getMessage());
}
}

@Retryable注解
被注解的方法发生异常时会重试
value:指定发生的异常进行重试
include:和value一样,默认空,当exclude也为空时,所有异常都重试
exclude:指定异常不重试,默认空,当include也为空时,所有异常都重试
maxAttemps:重试次数,默认3
backoff:重试补偿机制,默认没有

@Backoff注解
delay:指定延迟后重试
multiplier:指定延迟的倍数,比如delay=5000l,multiplier=2时,第一次重试为5秒后,第二次为10秒,第三次为20秒

@Recover
当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调

添加@EnableRetry注解,启用重试功能

package hello;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.retry.annotation.EnableRetry;

@SpringBootApplication
@EnableRetry
public class Application {

    public static void main(String[] args) throws Exception {
        ApplicationContext annotationContext = new AnnotationConfigApplicationContext("hello");
        RemoteService remoteService = annotationContext.getBean("remoteService", RemoteService.class);
        remoteService.call();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值