Better handling on 429

This commit is contained in:
Benoit Marty 2021-04-01 13:51:16 +02:00
parent 1f2d6bea21
commit 0bc864fc37
3 changed files with 18 additions and 4 deletions

View File

@ -37,6 +37,18 @@ fun Throwable.shouldBeRetried(): Boolean {
|| (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED) || (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
} }
/**
* Get the retry delay in case of rate limit exceeded error, adding 100 ms, of defaultValue otherwise
*/
fun Throwable.getRetryDelay(defaultValue: Long): Long {
return (this as? Failure.ServerError)
?.error
?.takeIf { it.code == MatrixError.M_LIMIT_EXCEEDED }
?.retryAfterMillis
?.plus(100L)
?: defaultValue
}
fun Throwable.isInvalidPassword(): Boolean { fun Throwable.isInvalidPassword(): Boolean {
return this is Failure.ServerError return this is Failure.ServerError
&& error.code == MatrixError.M_FORBIDDEN && error.code == MatrixError.M_FORBIDDEN

View File

@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.network
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.getRetryDelay
import org.matrix.android.sdk.api.failure.shouldBeRetried import org.matrix.android.sdk.api.failure.shouldBeRetried
import org.matrix.android.sdk.internal.network.ssl.CertUtil import org.matrix.android.sdk.internal.network.ssl.CertUtil
import retrofit2.HttpException import retrofit2.HttpException
@ -68,8 +69,9 @@ internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErr
?.also { unrecognizedCertificateException -> throw unrecognizedCertificateException } ?.also { unrecognizedCertificateException -> throw unrecognizedCertificateException }
if (canRetry && currentRetryCount++ < maxRetriesCount && exception.shouldBeRetried()) { if (canRetry && currentRetryCount++ < maxRetriesCount && exception.shouldBeRetried()) {
delay(currentDelay) // In case of 429, ensure we wait enough
currentDelay = (currentDelay * 2L).coerceAtMost(maxDelayBeforeRetry) delay(currentDelay.coerceAtLeast(exception.getRetryDelay(0)))
currentDelay = currentDelay.times(2L).coerceAtMost(maxDelayBeforeRetry)
// Try again (loop) // Try again (loop)
} else { } else {
throw when (exception) { throw when (exception) {

View File

@ -24,6 +24,7 @@ import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.failure.getRetryDelay
import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.Cancelable
@ -148,8 +149,7 @@ internal class EventSenderProcessorCoroutine @Inject constructor(
task.markAsFailedOrRetry(exception, 0) task.markAsFailedOrRetry(exception, 0)
} }
(exception is Failure.ServerError && exception.error.code == MatrixError.M_LIMIT_EXCEEDED) -> { (exception is Failure.ServerError && exception.error.code == MatrixError.M_LIMIT_EXCEEDED) -> {
val delay = exception.error.retryAfterMillis?.plus(100) ?: 3_000 task.markAsFailedOrRetry(exception, exception.getRetryDelay(3_000))
task.markAsFailedOrRetry(exception, delay)
} }
exception is CancellationException -> { exception is CancellationException -> {
Timber.v("## $task has been cancelled, try next task") Timber.v("## $task has been cancelled, try next task")