diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt index e0ee9f36ba..17362ff8d7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt @@ -37,6 +37,18 @@ fun Throwable.shouldBeRetried(): Boolean { || (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 { return this is Failure.ServerError && error.code == MatrixError.M_FORBIDDEN diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt index 24b9b83f75..d9f102c7e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.network import kotlinx.coroutines.CancellationException import kotlinx.coroutines.delay 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.internal.network.ssl.CertUtil import retrofit2.HttpException @@ -68,8 +69,9 @@ internal suspend inline fun executeRequest(globalErrorReceiver: GlobalErr ?.also { unrecognizedCertificateException -> throw unrecognizedCertificateException } if (canRetry && currentRetryCount++ < maxRetriesCount && exception.shouldBeRetried()) { - delay(currentDelay) - currentDelay = (currentDelay * 2L).coerceAtMost(maxDelayBeforeRetry) + // In case of 429, ensure we wait enough + delay(currentDelay.coerceAtLeast(exception.getRetryDelay(0))) + currentDelay = currentDelay.times(2L).coerceAtMost(maxDelayBeforeRetry) // Try again (loop) } else { throw when (exception) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt index 2972332989..a5c09f5ff6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.failure.Failure 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.events.model.Event import org.matrix.android.sdk.api.util.Cancelable @@ -148,8 +149,7 @@ internal class EventSenderProcessorCoroutine @Inject constructor( task.markAsFailedOrRetry(exception, 0) } (exception is Failure.ServerError && exception.error.code == MatrixError.M_LIMIT_EXCEEDED) -> { - val delay = exception.error.retryAfterMillis?.plus(100) ?: 3_000 - task.markAsFailedOrRetry(exception, delay) + task.markAsFailedOrRetry(exception, exception.getRetryDelay(3_000)) } exception is CancellationException -> { Timber.v("## $task has been cancelled, try next task")