From 9c7ba58114e6824e2b24bd9a7b4936d01055fd75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Thu, 4 Dec 2025 11:06:14 +0100 Subject: [PATCH] Don't re-schedule notification fetches if the cause of the failure is `SessionRestorationException`, since that means it'll most likely fail again --- .../matrix/api/exception/ClientException.kt | 6 +++++- .../DefaultNotifiableEventResolver.kt | 2 +- .../impl/workmanager/FetchNotificationsWorker.kt | 15 +++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt index 30f77e7b5e..52b1577bf0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt @@ -10,7 +10,11 @@ package io.element.android.libraries.matrix.api.exception sealed class ClientException(message: String, val details: String?, cause: Throwable? = null) : Exception(message, cause) { class Generic(message: String, details: String?, cause: Throwable? = null) : ClientException(message, details, cause) - class MatrixApi(val kind: ErrorKind, val code: String, message: String, details: String?, cause: Throwable? = null) : ClientException(message, details, cause) + class MatrixApi(val kind: ErrorKind, val code: String, message: String, details: String?, cause: Throwable? = null) : ClientException( + message = message, + details = details, + cause = cause + ) class Other(message: String, cause: Throwable? = null) : ClientException(message, null, cause) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt index 763747d7ce..e3d0f21d03 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt @@ -99,7 +99,7 @@ class DefaultNotifiableEventResolver( ): ResolvePushEventsResult { Timber.d("Queueing notifications: $notificationEventRequests") val client = matrixClientProvider.getOrRestore(sessionId).getOrElse { - return Result.failure(IllegalStateException("Couldn't get or restore client for session $sessionId")) + return Result.failure(it) } val ids = notificationEventRequests.groupBy { it.roomId } .mapValues { (_, requests) -> diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt index be8db1a11e..ccc0a02749 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt @@ -22,6 +22,7 @@ import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.di.annotations.ApplicationContext +import io.element.android.libraries.matrix.api.auth.SessionRestorationException import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.push.api.push.NotificationEventRequest import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent @@ -63,9 +64,9 @@ class FetchNotificationsWorker( return@withContext Result.retry() } - val failedSyncForSessions = mutableSetOf() + val failedSyncForSessions = mutableMapOf() - val groupedRequests = requests.groupBy { it.sessionId } + val groupedRequests = requests.groupBy { it.sessionId }.toMutableMap() for ((sessionId, notificationRequests) in groupedRequests) { Timber.d("Processing notification requests for session $sessionId") eventResolver.resolveEvents(sessionId, notificationRequests) @@ -75,7 +76,7 @@ class FetchNotificationsWorker( (queue.results as MutableSharedFlow).emit(requests to result) }, onFailure = { - failedSyncForSessions += sessionId + failedSyncForSessions[sessionId] = it Timber.e(it, "Failed to resolve notification events for session $sessionId") } ) @@ -83,7 +84,13 @@ class FetchNotificationsWorker( // If there were failures for whole sessions, we retry all their requests if (failedSyncForSessions.isNotEmpty()) { - for (failedSessionId in failedSyncForSessions) { + @Suppress("LoopWithTooManyJumpStatements") + for ((failedSessionId, exception) in failedSyncForSessions) { + if (exception.cause is SessionRestorationException) { + Timber.e(exception, "Session $failedSessionId could not be restored, not retrying notification fetching") + groupedRequests.remove(failedSessionId) + continue + } val requestsToRetry = groupedRequests[failedSessionId] ?: continue Timber.d("Re-scheduling ${requestsToRetry.size} failed notification requests for session $failedSessionId") workManagerScheduler.submit(