Как выполнить экспоненциальную повторную попытку повторения на kotlin coroutines

Я использую kotlin coroutines для сетевого запроса, используя метод расширения, чтобы вызвать класс в модификации, подобный этому

public suspend fun <T : Any> Call<T>.await(): T { return suspendCancellableCoroutine { continuation -> enqueue(object : Callback<T> { override fun onResponse(call: Call<T>?, response: Response<T?>) { if (response.isSuccessful) { val body = response.body() if (body == null) { continuation.resumeWithException( NullPointerException("Response body is null") ) } else { continuation.resume(body) } } else { continuation.resumeWithException(HttpException(response)) } } override fun onFailure(call: Call<T>, t: Throwable) { // Don't bother with resuming the continuation if it is already cancelled. if (continuation.isCancelled) return continuation.resumeWithException(t) } }) registerOnCompletion(continuation) } } 

то из вызывающей стороны я использую метод выше, как это

 private fun getArticles() = launch(UI) { loading.value = true try { val networkResult = api.getArticle().await() articles.value = networkResult }catch (e: Throwable){ e.printStackTrace() message.value = e.message }finally { loading.value = false } } 

Я хочу, чтобы экспоненциальный повторить этот вызов api в некотором случае ie (IOException), как я могу его достичь?

Я бы предложил написать вспомогательную функцию более высокого порядка для вашей логики повтора. Вы можете использовать следующую реализацию для запуска:

 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 } 

Использование этой функции очень сложно:

 val networkResult = retryIO { api.getArticle().await() } 

Вы можете изменить параметры повтора в каждом конкретном случае, например:

 val networkResult = retryIO(times = 3) { api.doSomething().await() } 

Вы также можете полностью изменить реализацию retryIO в соответствии с потребностями вашего приложения. Например, вы можете жестко закодировать все параметры повтора, избавиться от ограничения количества попыток, изменить значения по умолчанию и т. Д.