Skip to content

Instantly share code, notes, and snippets.

@Andrew0000
Last active May 30, 2024 08:52
Show Gist options
  • Save Andrew0000/a9e0a893a68967afba0e2b631a9f5018 to your computer and use it in GitHub Desktop.
Save Andrew0000/a9e0a893a68967afba0e2b631a9f5018 to your computer and use it in GitHub Desktop.
suspend fun <T> retrying
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
suspend fun <T> retrying(
timesMax: Int = 3,
delayMillis: (Int) -> Long = { (it + 1) * 1000L },
needRetry: (Int, Throwable) -> Boolean = { _, _ -> true },
block: suspend () -> T,
onResult: suspend (T) -> Unit,
onFinalError: suspend (Throwable) -> Unit,
finally: suspend () -> Unit = {},
) {
try {
if (timesMax <= 0) {
onFinalError(IllegalArgumentException("timesMax: $timesMax"))
return
}
for (triedTimes in 0..timesMax) {
try {
val result = block()
onResult(result)
return
} catch (t: Throwable) {
t.rethrowIfCancellation()
if (triedTimes >= (timesMax - 1) || !needRetry(triedTimes, t)) {
onFinalError(t)
return
}
delay(delayMillis(triedTimes))
}
}
} finally {
finally()
}
}
suspend fun <T> retrying(
timesMax: Int = 3,
delayMillis: (Int) -> Long = { (it + 1) * 1000L },
needRetry: (Int, Throwable) -> Boolean = { _, _ -> true },
block: suspend () -> T,
): T {
if (timesMax <= 0) {
throw IllegalArgumentException("timesMax: $timesMax")
}
for (triedTimes in 0..timesMax) {
try {
return block()
} catch (t: Throwable) {
t.rethrowIfCancellation()
if (triedTimes >= (timesMax - 1) || !needRetry(triedTimes, t)) {
throw t
}
delay(delayMillis(triedTimes))
}
}
throw IllegalStateException("Retrying completed; Not expected to get here!")
}
/*
* https://kotlinlang.org/docs/cancellation-and-timeouts.html#run-non-cancellable-block
* https://stackoverflow.com/a/62221582/2276980
*/
fun Throwable.rethrowIfCancellation() {
if (this is CancellationException) {
throw this
}
}
@Andrew0000
Copy link
Author

val loaded = retrying(
timesMax = 10,
delayMillis = { ((it + 1) * 1000L).coerceAtMost(10_000L) }
) {
Api.client.get(Url(url)).readBytes()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment