[web] check end state before terminating (#31136)

* check and log unexpected end states before terminating Recurly subscriptions
* update finalize and rollback scripts to only postpone active subscriptions

GitOrigin-RevId: 7fe6ffa56cb8ddf19133eb0cb59e39fd783430b7
This commit is contained in:
Kristina
2026-01-30 09:06:12 +00:00
committed by Copybot
parent a370a72a5a
commit d6fbed2a74
3 changed files with 80 additions and 38 deletions
@@ -431,21 +431,23 @@ async function performCutover(
}
)
// Step 3: Postpone Recurly billing by +10 years
const currentBillingDate = new Date(
recurlySubscription.current_period_ends_at
)
const postponedDate = new Date(currentBillingDate)
postponedDate.setFullYear(currentBillingDate.getFullYear() + 10)
// Step 3: Postpone Recurly billing by +10 years if Recurly subscription is active
if (recurlySubscription.state !== 'canceled') {
const currentBillingDate = new Date(
recurlySubscription.current_period_ends_at
)
const postponedDate = new Date(currentBillingDate)
postponedDate.setFullYear(currentBillingDate.getFullYear() + 10)
try {
await RecurlyWrapper.promises.apiRequest({
url: `subscriptions/${recurlySubscription.uuid}/postpone`,
qs: { bulk: true, next_bill_date: postponedDate },
method: 'PUT',
})
} catch (err) {
throw new Error(`Failed to postpone Recurly billing: ${err.message}`)
try {
await RecurlyWrapper.promises.apiRequest({
url: `subscriptions/${recurlySubscription.uuid}/postpone`,
qs: { bulk: true, next_bill_date: postponedDate },
method: 'PUT',
})
} catch (err) {
throw new Error(`Failed to postpone Recurly billing: ${err.message}`)
}
}
// Step 4: Remove migration metadata from Stripe
@@ -301,30 +301,35 @@ async function performRollback(
}
)
// Step 3: Un-postpone Recurly billing by 10 years
// Step 3: Un-postpone Recurly billing by 10 years if next billing period was postponed
const currentPeriodEnd = new Date(recurlySubscription.current_period_ends_at)
const nextBillingDate = new Date(currentPeriodEnd)
nextBillingDate.setFullYear(currentPeriodEnd.getFullYear() - 10)
const targetBillingDateIsInFuture = nextBillingDate.getTime() > Date.now()
const nineYearsFromNow = new Date()
nineYearsFromNow.setFullYear(new Date().getFullYear() + 9)
if (targetBillingDateIsInFuture) {
try {
await RecurlyWrapper.promises.apiRequest({
url: `subscriptions/${recurlySubscriptionId}/postpone`,
qs: { bulk: true, next_bill_date: nextBillingDate },
method: 'PUT',
})
} catch (err) {
if (currentPeriodEnd > nineYearsFromNow) {
const nextBillingDate = new Date(currentPeriodEnd)
nextBillingDate.setFullYear(currentPeriodEnd.getFullYear() - 10)
const targetBillingDateIsInFuture = nextBillingDate.getTime() > Date.now()
if (targetBillingDateIsInFuture) {
try {
await RecurlyWrapper.promises.apiRequest({
url: `subscriptions/${recurlySubscriptionId}/postpone`,
qs: { bulk: true, next_bill_date: nextBillingDate },
method: 'PUT',
})
} catch (err) {
throw new ReportError(
'rolled-back-recurly-restore-failed',
`Restored Mongo but failed to restore Recurly billing: ${err.message}`
)
}
} else {
throw new ReportError(
'rolled-back-recurly-restore-failed',
`Restored Mongo but failed to restore Recurly billing: ${err.message}`
`Restored Mongo and Recurly but failed to restore Recurly billing: target next billing date is in the past (${nextBillingDate.toISOString()})`
)
}
} else {
throw new ReportError(
'rolled-back-recurly-restore-failed',
`Restored Mongo and Recurly but failed to restore Recurly billing: target next billing date is in the past (${nextBillingDate.toISOString()})`
)
}
// Step 4: Restore migration metadata to Stripe