Use Cron/scheduleFrequently for subscription redemption

This commit is contained in:
Sasha Weiss 2026-05-13 16:14:19 -07:00 committed by GitHub
parent 4d8b53474f
commit 8a0e1a9a2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 59 deletions

View File

@ -193,6 +193,50 @@ public class AppEnvironment: NSObject {
operation: { try await identityKeyMismatchManager.validateLocalPniIdentityKeyIfNecessary() },
)
let backupSubscriptionManager = DependenciesBridge.shared.backupSubscriptionManager
cron.scheduleFrequently(
mustBeRegistered: true,
mustBeConnected: true,
operation: { try await backupSubscriptionManager.redeemSubscriptionIfNecessary() },
handleResult: {
switch $0 {
case .success, .failure(is CancellationError):
break
case .failure(let error):
Logger.warn("Terminally failed to redeem Backups subscription! \(error)")
}
},
)
let backupTestFlightEntitlementManager = DependenciesBridge.shared.backupTestFlightEntitlementManager
cron.scheduleFrequently(
mustBeRegistered: true,
mustBeConnected: true,
operation: { try await backupTestFlightEntitlementManager.renewEntitlementIfNecessary() },
handleResult: {
switch $0 {
case .success, .failure(is CancellationError):
break
case .failure(let error):
Logger.warn("Terminally failed to redeem Backups TestFlight subscription! \(error)")
}
},
)
cron.scheduleFrequently(
mustBeRegistered: true,
mustBeConnected: true,
operation: { try await DonationSubscriptionManager.redeemSubscriptionIfNecessary() },
handleResult: {
switch $0 {
case .success, .failure(is CancellationError):
break
case .failure(let error):
Logger.warn("Terminally failed to redeem Donations subscription! \(error)")
}
},
)
appReadiness.runNowOrWhenAppWillBecomeReady {
self.badgeManager.startObservingChanges(in: DependenciesBridge.shared.databaseChangeObserver)
self.appIconBadgeUpdater.startObserving()
@ -203,8 +247,6 @@ public class AppEnvironment: NSObject {
let attachmentBackfillManager = DependenciesBridge.shared.attachmentBackfillManager
let backupExportJobRunner = DependenciesBridge.shared.backupExportJobRunner
let backupIdService = DependenciesBridge.shared.backupIdService
let backupSubscriptionManager = DependenciesBridge.shared.backupSubscriptionManager
let backupTestFlightEntitlementManager = DependenciesBridge.shared.backupTestFlightEntitlementManager
let callRecordStore = DependenciesBridge.shared.callRecordStore
let callRecordQuerier = DependenciesBridge.shared.callRecordQuerier
let db = DependenciesBridge.shared.db
@ -305,31 +347,6 @@ public class AppEnvironment: NSObject {
Task {
await self.avatarHistoryManager.cleanupOrphanedImages()
}
Task {
do {
try await backupSubscriptionManager.redeemSubscriptionIfNecessary()
} catch {
owsFailDebug("Failed to redeem Backup subscription in launch job: \(error)")
}
}
Task {
do {
try await backupTestFlightEntitlementManager.renewEntitlementIfNecessary()
} catch {
owsFailDebug("Failed to renew Backup entitlement for TestFlight in launch job: \(error)")
}
}
Task {
await DonationSubscriptionManager.performMigrationToStorageServiceIfNecessary()
do {
try await DonationSubscriptionManager.redeemSubscriptionIfNecessary()
} catch {
owsFailDebug("Failed to redeem subscription in launch job: \(error)")
}
}
}
}
}

View File

@ -263,7 +263,10 @@ final class BackupEnablingManager {
private func enablePaidPlanWithoutStoreKit() async throws(SheetDisplayableError) {
do {
try await backupTestFlightEntitlementManager.acquireEntitlement()
await db.awaitableWrite { tx in
backupTestFlightEntitlementManager.setRenewEntitlementIsNecessary(tx: tx)
}
try await backupTestFlightEntitlementManager.renewEntitlementIfNecessary()
} catch where error.isNetworkFailureOrTimeout {
throw .networkError
} catch {

View File

@ -9,8 +9,6 @@ import DeviceCheck
/// Responsible for managing paid-tier Backup entitlements for TestFlight users,
/// who aren't able to use StoreKit or perform real-money transactions.
public protocol BackupTestFlightEntitlementManager {
func acquireEntitlement() async throws
func setRenewEntitlementIsNecessary(tx: DBWriteTransaction)
func renewEntitlementIfNecessary() async throws
}
@ -62,13 +60,7 @@ final class BackupTestFlightEntitlementManagerImpl: BackupTestFlightEntitlementM
// MARK: -
func acquireEntitlement() async throws {
try await serialTaskQueue.run {
try await _acquireEntitlement()
}
}
private func _acquireEntitlement() async throws {
private func acquireEntitlement() async throws {
owsPrecondition(BuildFlags.Backups.avoidStoreKitForTesters)
guard TSConstants.isUsingProductionService else {
@ -109,6 +101,12 @@ final class BackupTestFlightEntitlementManagerImpl: BackupTestFlightEntitlementM
}
func renewEntitlementIfNecessary() async throws {
try await serialTaskQueue.run {
try await _renewEntitlementIfNecessary()
}
}
private func _renewEntitlementIfNecessary() async throws {
let (
isRegisteredPrimaryDevice,
isCurrentlyTesterBuild,

View File

@ -64,27 +64,6 @@ public extension Notification.Name {
/// similar things but designed around In-App Payments (StoreKit) and paid-tier
/// Backups.
public enum DonationSubscriptionManager {
public static func performMigrationToStorageServiceIfNecessary() async {
let hasMigratedToStorageService = SSKEnvironment.shared.databaseStorageRef.read { transaction in
subscriptionKVS.getBool(hasMigratedToStorageServiceKey, defaultValue: false, transaction: transaction)
}
guard !hasMigratedToStorageService else { return }
Logger.info("[Donations] Migrating to storage service")
await SSKEnvironment.shared.databaseStorageRef.awaitableWrite { transaction in
subscriptionKVS.setBool(true, key: hasMigratedToStorageServiceKey, transaction: transaction)
let localProfile = SSKEnvironment.shared.profileManagerRef.localUserProfile(tx: transaction)
let displayBadgesOnProfile = localProfile?.badges.count == localProfile?.visibleBadges.count
setDisplayBadgesOnProfile(displayBadgesOnProfile, transaction: transaction)
}
SSKEnvironment.shared.storageServiceManagerRef.recordPendingLocalAccountUpdates()
}
// MARK: -
private static var receiptCredentialRedemptionJobQueue: DonationReceiptCredentialRedemptionJobQueue {
SSKEnvironment.shared.donationReceiptCredentialRedemptionJobQueue
@ -108,7 +87,6 @@ public enum DonationSubscriptionManager {
fileprivate static let mostRecentlyExpiredGiftBadgeIDKey = "mostRecentlyExpiredGiftBadgeIDKey"
fileprivate static let showExpirySheetOnHomeScreenKey = "showExpirySheetOnHomeScreenKey"
fileprivate static let mostRecentSubscriptionPaymentMethodKey = "mostRecentSubscriptionPaymentMethod"
fileprivate static let hasMigratedToStorageServiceKey = "hasMigratedToStorageServiceKey"
// MARK: -