在Reactor中自定义重试

时间:2018-11-10 20:46:50

标签: kotlin spring-webflux project-reactor retry-logic

我试图基于Reactor额外程序包的功能在Kotlin和Reactor中实现重试逻辑。我想做的是传递持续时间列表,在每个context.iteration上我都获得列表的第(iteration-1)个元素。它可以部分运行,尽管我提供了最大的重试次数(列表的大小),但我总是在上一次迭代中得到IndexOutOfBoundsException,这比我想要的要多。但是,在给定的持续时间和“正确”的次数(肯定是因为IndexOutOfBoundsException阻止了更多次)的情况下,重试仍在运行,只有这种例外(这是根本原因)困扰着我。

这是我自定义的BackOff界面:

interface MyCustomBackoff : Backoff {
    companion object {
        fun getBackoffDelay(backoffList: List<Duration>): (IterationContext<*>) -> BackoffDelay {
            return { context -> BackoffDelay(backoffList[(context.iteration() - 1).toInt()]) }
        }
    }
}

我的Kotlin扩展名是:

fun <T> Mono<T>.retryCustomBackoffs(backoffList: List<Duration>, doOnRetry: ((RetryContext<T>) -> Unit)? = null): Mono<T> {
    val retry = Retry.any<T>().retryMax(backoffList.size.toLong()).backoff(MyCustomBackoff.getBackoffDelay(backoffList))

    return if (doOnRetry == null) {
        this.retryWhen(retry)
    }
    else {
        this.retryWhen(retry.doOnRetry(doOnRetry))
    }
}

我在这里想念什么?

1 个答案:

答案 0 :(得分:1)

如果您查看reactor.retry.AbstractRetry#calculateBackoff,可能会发现名为BackoffDelay的特殊RETRY_EXHAUSTED。它在retryContext.iteration() > maxIterations之后的>=(不是backoff.apply(retryContext))时返回

if (retryContext.iteration() > maxIterations || Instant.now(clock).plus(jitteredBackoff).isAfter(timeoutInstant))
    return RETRY_EXHAUSTED;

因此,如果列表中有2个自定义退避延迟,则calculateBackoff会产生3个退避延迟。

您可以这样更改MyCustomBackoff(对Java来说请原谅,我对Kotlin不熟悉):

public interface MyCustomBackoff extends Backoff {
    static Backoff getBackoffDelay(List<Duration> backoffList) {
        return context -> context.iteration() <= backoffList.size() ?
                new BackoffDelay(backoffList.get(Long.valueOf(context.iteration() - 1).intValue())) :
                new BackoffDelay(Duration.ZERO);
    }
}