You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Retrofit的RxJava Single请求添加重试延迟/指数退避?

实现带延迟/指数退避的RxJava Single重试机制

嗨,这个需求其实RxJava已经帮我们准备好了现成的方案,不用自己手动实现延迟逻辑~你现在用的retry()方法虽然能指定重试次数和断言,但没法控制重试间隔,这时候换成retryWhen()就能完美解决问题,它允许我们自定义重试的时机和延迟策略。

核心思路

retryWhen()接收一个Flowable<Throwable>作为输入,我们可以在这个流里:

  1. 保留你原来的错误断言逻辑,只对符合条件的错误进行重试;
  2. 绑定重试次数,控制最多重试3次;
  3. 加入延迟或指数退避逻辑,让重试间隔逐渐拉长。

方案1:固定延迟重试

如果希望每次重试都间隔固定时间(比如1秒),可以用下面的代码替换你原来的applySchIoAndRetry()方法:

import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.core.SingleTransformer;
import io.reactivex.rxjava3.schedulers.Schedulers;
import io.reactivex.rxjava3.exceptions.Exceptions;
import retrofit2.HttpException;
import java.util.concurrent.TimeUnit;

public <T> SingleTransformer<T, T> applySchIoAndRetry() {
    return upstream -> upstream
            .subscribeOn(Schedulers.io())
            .retryWhen(throwableFlowable -> throwableFlowable
                    // 把错误流和重试次数(1-3)绑定,控制最多重试3次
                    .zipWith(Flowable.range(1, 3), (throwable, retryCount) -> {
                        // 保留你原来的断言逻辑:仅非400的HttpException才重试
                        if (throwable instanceof HttpException) {
                            HttpException exception = (HttpException) throwable;
                            if (exception.code() != 400) {
                                return retryCount;
                            }
                        }
                        // 不符合重试条件,直接抛出错误终止流程
                        throw Exceptions.propagate(throwable);
                    })
                    // 每次重试前延迟1秒
                    .flatMap(retryCount -> Flowable.timer(1, TimeUnit.SECONDS))
            );
}

方案2:指数退避重试

如果想优化重试策略,比如第一次延迟1秒,第二次2秒,第三次4秒(指数增长),避免短时间内频繁请求给服务器造成压力,只需要修改延迟计算逻辑即可:

public <T> SingleTransformer<T, T> applySchIoAndRetryWithExponentialBackoff() {
    return upstream -> upstream
            .subscribeOn(Schedulers.io())
            .retryWhen(throwableFlowable -> throwableFlowable
                    .zipWith(Flowable.range(1, 3), (throwable, retryCount) -> {
                        if (throwable instanceof HttpException) {
                            HttpException exception = (HttpException) throwable;
                            if (exception.code() != 400) {
                                return retryCount;
                            }
                        }
                        throw Exceptions.propagate(throwable);
                    })
                    // 指数退避:第n次重试延迟 2^(n-1) 秒
                    .flatMap(retryCount -> {
                        long delaySeconds = (long) Math.pow(2, retryCount - 1);
                        return Flowable.timer(delaySeconds, TimeUnit.SECONDS);
                    })
            );
}

关键细节说明

  • 重试次数控制:Flowable.range(1,3)表示最多重试3次,和你原来的retry(3)逻辑一致(原始请求+3次重试,共4次请求);
  • 错误断言保留:在zipWith的lambda里先判断错误是否符合重试条件,不符合就直接抛出异常终止重试;
  • 延迟实现:用Flowable.timer()生成延迟信号,当这个信号发射时,RxJava就会触发重试;
  • 异常处理:用Exceptions.propagate()包装checked exception,避免lambda里的编译错误。

你的调用代码完全不需要修改,还是像原来一样用compose()应用这个Transformer就行:

public Single<Foo> bar() {
    return apiService.foobar()
            .compose(rxHelper.applySchIoAndRetry());
}

内容的提问来源于stack exchange,提问作者Rajath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:33:40