From a7fb84e7e6e6bda8331a66dbe4c6f34925e8c83d Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Mon, 17 Mar 2025 15:05:11 -0300 Subject: [PATCH] Improve error code handling in recurring context job. --- .../jobs/InAppPaymentRecurringContextJob.kt | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt index 238d56b42b..6f86705be3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt @@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.jobmanager.Job import org.thoughtcrime.securesms.jobmanager.JobManager.Chain import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription.ChargeFailure import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription.Subscription @@ -117,6 +118,10 @@ class InAppPaymentRecurringContextJob private constructor( } override fun getNextRunAttemptBackoff(pastAttemptCount: Int, exception: java.lang.Exception): Long { + if (exception is InAppPaymentRetryException && exception.cause is NonSuccessfulResponseCodeException) { + return super.getNextRunAttemptBackoff(pastAttemptCount, exception) + } + val inAppPayment = SignalDatabase.inAppPayments.getById(inAppPaymentId) return if (inAppPayment != null) { when (inAppPayment.data.paymentMethodType) { @@ -186,7 +191,20 @@ class InAppPaymentRecurringContextJob private constructor( endOfCurrentSubscriptionPeriod: Long ): Boolean { @Suppress("UsePropertyAccessSyntax") - val whoAmIResponse = AppDependencies.signalServiceAccountManager.getWhoAmI() + val whoAmIResponse = try { + AppDependencies.signalServiceAccountManager.getWhoAmI() + } catch (e: NonSuccessfulResponseCodeException) { + warning("Failed to download whoAmI information for user: HTTP ${e.code}", e) + if (isRetryableErrorCode(e.code)) { + info("Retrying later for code ${e.code}") + throw InAppPaymentRetryException(e) + } else { + throw e + } + } catch (e: IOException) { + info("Retrying for network exception.") + throw InAppPaymentRetryException(e) + } return when (inAppPayment.type) { InAppPaymentType.RECURRING_BACKUP -> { @@ -205,6 +223,10 @@ class InAppPaymentRecurringContextJob private constructor( } } + private fun isRetryableErrorCode(code: Int): Boolean { + return (code >= 500 || code == 429) && code != 508 + } + private fun markInAppPaymentCompleted(inAppPayment: InAppPaymentTable.InAppPayment) { SignalDatabase.inAppPayments.update( inAppPayment = inAppPayment.copy( @@ -484,6 +506,12 @@ class InAppPaymentRecurringContextJob private constructor( throw Exception(applicationError) } + 508 -> { + warning("Loop detected on server. Failing.", applicationError) + updateInAppPaymentWithGenericRedemptionError(inAppPayment) + throw Exception(applicationError) + } + else -> { warning("Encountered a server error.", applicationError)