Ruslan Sierov
07/24/2024, 8:19 AMarrow.resiliencedoWhilesuspend fun <L, R> withExponentialRetries(
    until: (Either<L, R>) -> Boolean = { it.isRight() },
    retries: Long = 4,
    delay: Duration = 500.milliseconds,
    maxDelayCap: Duration = Duration.INFINITE,
    block: suspend () -> Either<L, R>,
): Either<L, R> = Schedule.exponential<Either<L, R>>(base = delay)
    .doWhile { _, duration ->
        val proceedExponentially = duration < maxDelayCap
        // this delay is needed before switching to spaced
        // scheduler so we don't immediately call [block]
        if (!proceedExponentially) delay(maxDelayCap)
        proceedExponentially
    }
    .andThen(Schedule.spaced(maxDelayCap))
    .and(Schedule.recurs(retries))
    .doUntil { yielded, _ -> until(yielded) }
    .zipRight(Schedule.identity())
    .repeat(block)