I would suggest to write a helper higher-order function for your retry logic. You can use the following implementation for a start:
suspend fun <T> retryIO(
times: Int = Int.MAX_VALUE,
initialDelay: Long = 100, // 0.1 second
maxDelay: Long = 1000, // 1 second
factor: Double = 2.0,
block: suspend () -> T): T
{
var currentDelay = initialDelay
repeat(times - 1) {
try {
return block()
} catch (e: IOException) {
// you can log an error here and/or make a more finer-grained
// analysis of the cause to see if retry is needed
}
delay(currentDelay)
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
}
return block() // last attempt
}
Using this function is very strightforward:
val networkResult = retryIO { api.getArticle().await() }
You can change retry parameters on case-by-case basis, for example:
val networkResult = retryIO(times = 3) { api.doSomething().await() }
You can also completely change the implementation of retryIO to suit the needs of your application. For example, you can hard-code all the retry parameters, get rid of the limit on the number of retries, change defaults, etc.