diff --git a/Network/Ktor/src/main/kotlin/CreateHttpClient.kt b/Network/Ktor/src/main/kotlin/CreateHttpClient.kt index d964c8567..f14598047 100644 --- a/Network/Ktor/src/main/kotlin/CreateHttpClient.kt +++ b/Network/Ktor/src/main/kotlin/CreateHttpClient.kt @@ -30,6 +30,7 @@ import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.request import io.ktor.http.ContentType import io.ktor.http.HttpHeaders +import io.ktor.http.isSuccess import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json @@ -56,7 +57,7 @@ fun createHttpClient( } HttpResponseValidator { validateResponse { response -> - response.validateContentType { accepted, received -> + if (response.status.isSuccess()) response.validateContentType { accepted, received -> val url = response.request.url val method = response.request.method throw IllegalArgumentException("Expected Content-Type $accepted but got $received from $method on $url") diff --git a/Notifications/Registration/src/main/kotlin/AbstractNotificationsRegistrationWorker.kt b/Notifications/Registration/src/main/kotlin/AbstractNotificationsRegistrationWorker.kt index 234ffd5c8..5a7964bb2 100644 --- a/Notifications/Registration/src/main/kotlin/AbstractNotificationsRegistrationWorker.kt +++ b/Notifications/Registration/src/main/kotlin/AbstractNotificationsRegistrationWorker.kt @@ -23,6 +23,7 @@ import androidx.work.CoroutineWorker import androidx.work.ExistingWorkPolicy import androidx.work.NetworkType import androidx.work.OneTimeWorkRequest +import androidx.work.WorkInfo import androidx.work.WorkManager import androidx.work.WorkerParameters import androidx.work.await @@ -40,6 +41,7 @@ import io.ktor.http.isSuccess import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first import kotlinx.coroutines.tasks.await import okhttp3.OkHttpClient @@ -75,6 +77,9 @@ abstract class AbstractNotificationsRegistrationWorker( }.awaitAll() return if (outcomes.any { it == Outcome.ShouldRetry }) { Result.retry() + } else if (outcomes.any { it == Outcome.Failed }) { + SentryLog.i(TAG, "Work failed") + Result.failure() } else { SentryLog.i(TAG, "Work finished") Result.success() @@ -128,9 +133,10 @@ abstract class AbstractNotificationsRegistrationWorker( return workRequest.id } - suspend fun awaitWorkerCompletion(uuid: UUID) { + suspend fun awaitWorkerCompletion(uuid: UUID): Boolean { val workManager = WorkManager.getInstance(appCtx) - workManager.getWorkInfoByIdFlow(uuid).first { it?.state?.isFinished == true } + val workInfo = workManager.getWorkInfoByIdFlow(uuid).filterNotNull().first { it.state.isFinished } + return workInfo.state != WorkInfo.State.FAILED } @PublishedApi @@ -140,6 +146,7 @@ abstract class AbstractNotificationsRegistrationWorker( private enum class Outcome { Done, + Failed, ShouldRetry, } @@ -155,11 +162,11 @@ private fun handleUnsuccessfulResponse(response: HttpResponse): Outcome { } 401 -> { SentryLog.w(TAG, errorMessage) - Outcome.Done + Outcome.Failed } else -> { SentryLog.wtf(TAG, errorMessage) - Outcome.Done + Outcome.Failed } } } @@ -171,6 +178,6 @@ private fun handleNetworkOperationFailure(t: Throwable): Outcome { Outcome.ShouldRetry } else { SentryLog.wtf(TAG, errorMessage, t) - Outcome.Done + Outcome.Failed } } diff --git a/Notifications/Registration/src/main/kotlin/NotificationsRegistrationManager.kt b/Notifications/Registration/src/main/kotlin/NotificationsRegistrationManager.kt index 092fe4a2c..cf461bbd1 100644 --- a/Notifications/Registration/src/main/kotlin/NotificationsRegistrationManager.kt +++ b/Notifications/Registration/src/main/kotlin/NotificationsRegistrationManager.kt @@ -118,11 +118,11 @@ object NotificationsRegistrationManager : AssociatedUserDataCleanable { latestFcmToken.collectLatest { fcmToken -> userIdsFlow.collectLatest { userIds -> - while (true) { + do { awaitAnyNeedForUpdate(userIds, fcmToken, latestNotificationTopics) val id = AbstractNotificationsRegistrationWorker.schedule(workerClass) - AbstractNotificationsRegistrationWorker.awaitWorkerCompletion(id) // Don't loop immediately. - } + val didNotFail = AbstractNotificationsRegistrationWorker.awaitWorkerCompletion(id) // Don't loop immediately. + } while (didNotFail) } } }