When a background SDK task fails, react in the client (#6166)
- For initialization issues or errors, we just print and report them. - For panics (unrecoverable errors) we also crash the app.
This commit is contained in:
parent
b271e06973
commit
5b5224eb58
4 changed files with 88 additions and 3 deletions
|
|
@ -10,11 +10,14 @@ package io.element.android.libraries.matrix.impl
|
|||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.matrix.impl.core.SdkBackgroundTaskError
|
||||
import io.element.android.libraries.matrix.impl.mapper.toSessionData
|
||||
import io.element.android.libraries.matrix.impl.paths.getSessionPaths
|
||||
import io.element.android.libraries.matrix.impl.util.anonymizedTokens
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.rustcomponents.sdk.ClientDelegate
|
||||
import org.matrix.rustcomponents.sdk.ClientSessionDelegate
|
||||
|
|
@ -23,6 +26,7 @@ import timber.log.Timber
|
|||
import uniffi.matrix_sdk_common.BackgroundTaskFailureReason
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
private val loggerTag = LoggerTag("RustClientSessionDelegate")
|
||||
|
||||
|
|
@ -36,6 +40,7 @@ private val loggerTag = LoggerTag("RustClientSessionDelegate")
|
|||
class RustClientSessionDelegate(
|
||||
private val sessionStore: SessionStore,
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
private val analyticsService: AnalyticsService,
|
||||
coroutineDispatchers: CoroutineDispatchers,
|
||||
) : ClientSessionDelegate, ClientDelegate {
|
||||
// Used to ensure several calls to `didReceiveAuthError` don't trigger multiple logouts
|
||||
|
|
@ -122,8 +127,18 @@ class RustClientSessionDelegate(
|
|||
}
|
||||
|
||||
override fun onBackgroundTaskErrorReport(taskName: String, error: BackgroundTaskFailureReason) {
|
||||
// TODO actually implement the missing logic to report to sentry and crash the app
|
||||
Timber.tag(loggerTag.value).e("onBackgroundTaskErrorReport(taskName=$taskName, error=$error)")
|
||||
val backgroundTaskError = SdkBackgroundTaskError(taskName, error)
|
||||
Timber.e(backgroundTaskError, "SDK background task failed")
|
||||
analyticsService.trackError(backgroundTaskError)
|
||||
|
||||
if (error is BackgroundTaskFailureReason.Panic) {
|
||||
appCoroutineScope.launch {
|
||||
// The SDK failed in an unrecoverable way, so it will have indeterminate behaviour now.
|
||||
// Crash the app instead after a small delay to send the error.
|
||||
delay(500.milliseconds)
|
||||
throw backgroundTaskError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun retrieveSessionFromKeychain(userId: String): Session {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,12 @@ class RustMatrixClientFactory(
|
|||
private val sqliteStoreBuilderProvider: SqliteStoreBuilderProvider,
|
||||
private val workManagerScheduler: WorkManagerScheduler,
|
||||
) {
|
||||
private val sessionDelegate = RustClientSessionDelegate(sessionStore, appCoroutineScope, coroutineDispatchers)
|
||||
private val sessionDelegate = RustClientSessionDelegate(
|
||||
sessionStore = sessionStore,
|
||||
appCoroutineScope = appCoroutineScope,
|
||||
analyticsService = analyticsService,
|
||||
coroutineDispatchers = coroutineDispatchers
|
||||
)
|
||||
|
||||
suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) {
|
||||
val client = getBaseClientBuilder(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.core
|
||||
|
||||
import uniffi.matrix_sdk_common.BackgroundTaskFailureReason
|
||||
|
||||
/**
|
||||
* Error thrown when a background SDK task panics and can't recover.
|
||||
* @param task The name of the task that failed.
|
||||
* @param reason The cause of this error.
|
||||
*/
|
||||
class SdkBackgroundTaskError(
|
||||
task: String,
|
||||
reason: BackgroundTaskFailureReason,
|
||||
) : Error() {
|
||||
override val message: String = run {
|
||||
val message = when (reason) {
|
||||
is BackgroundTaskFailureReason.EarlyTermination -> "Early termination"
|
||||
is BackgroundTaskFailureReason.Error -> "Error: ${reason.error}"
|
||||
is BackgroundTaskFailureReason.Panic -> buildString {
|
||||
append("Panic (unrecoverable): ")
|
||||
reason.message?.let { append(it) }
|
||||
reason.panicBacktrace?.let {
|
||||
append("\n")
|
||||
append(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
"SDK background task '$task' failure: \n$message"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue