Пользовательская повторная попытка в Reactor

Я пытался реализовать логику повтора в Kotlin и Reactor на основе функций дополнительного пакета Reactor. Я пытаюсь передать список длительностей, и на каждом context.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))
    }
}

Что мне здесь не хватает?


person Peter    schedule 10.11.2018    source источник


Ответы (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 настраиваемых отсрочки отсрочки, будет 3 отсрочки, сгенерированных calculateBackoff.

Вы можете изменить свой 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);
    }
}
person Alexander Pankin    schedule 12.11.2018
comment
Большое вам спасибо, я пропустил это! - person Peter; 12.11.2018
comment
На самом деле это похоже на проблему. Я думаю, calculateBackoff следует проверить состояние истощения, а затем позвонить backoff.apply(retryContext). Я спрошу об этом на Github. - person Alexander Pankin; 12.11.2018
comment
Мне это тоже кажется нелогичным. Спасибо, что продолжили! - person Peter; 13.11.2018