but not sure how will it play out with coroutines ...
# ktor
d
but not sure how will it play out with coroutines and stuff
c
both coroutines and ktor http client need re-try facilities but not yet introduced
for now you can simply run a coroutine in a loop and await until success
d
Once I saw a snippit Roman posted a while back (needs adapting for new coroutines):
Copy code
uspend 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
}
Just for retry though...
c
The disadvantage is that you can't use it with child coroutines
since a failing child cause the whole job tree to fail
in spite of repeat and catch-block
so a
coroutineScope { }
is required at least in this case
d
Thanks for the comments, we're currently using it with old coroutines... I new it would need a bit of reworking. But at least for a Ktor client call it could do the trick, unless it's being called from an
async
block... This might be better @cy:
Copy code
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 CoroutineScope.() -> T): T  {
    var currentDelay = initialDelay
    repeat(times - 1) {
        try {
            return coroutineScope { 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 coroutineScope { block() } // last attempt
}
Truth is, event the original version shouldn't cancel anything with suspend functions running inside the block, since anyways any
async
run without a CoroutineScope will run on the GlobalScope...? So the changed version just allows to create new coroutines in the new scope inside the
block
lambda...
Unleass I'm missing something?
c
a acoroutine scope need to be inside of repeat
d
Corrected the code, but I'm still not sure why... You mean because if the block() throws an exception other than the one being caught, then the whole scope will be cancelled? So if all exceptions were caught, not just
IOException
then it would be better? I don't think I understand what you mean 100%...
c
because you can launch a couple of coroutines inside of the block
one of them can crash
d
I see, thanks!