mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
eea27a36a4
* Add `unicorn/prefer-node-protocol` * Revert non-web changes * Run `npm run lint:fix` (prefer-node-protocol) GitOrigin-RevId: c3cdd88ff9e6b3de6a4397d45935c4d026c1c1ed
186 lines
4.8 KiB
JavaScript
186 lines
4.8 KiB
JavaScript
import { Subscription } from '../../app/src/models/Subscription.js'
|
|
import RecurlyWrapper from '../../app/src/Features/Subscription/RecurlyWrapper.js'
|
|
import SubscriptionUpdater from '../../app/src/Features/Subscription/SubscriptionUpdater.js'
|
|
import minimist from 'minimist'
|
|
import { setTimeout } from 'node:timers/promises'
|
|
|
|
import util from 'node:util'
|
|
|
|
import pLimit from 'p-limit'
|
|
|
|
util.inspect.defaultOptions.maxArrayLength = null
|
|
|
|
const ScriptLogger = {
|
|
checkedSubscriptionsCount: 0,
|
|
mismatchSubscriptionsCount: 0,
|
|
allMismatchReasons: {},
|
|
|
|
// make sure all `allMismatchReasons` are displayed in the output
|
|
recordMismatch: (subscription, recurlySubscription) => {
|
|
const mismatchReasons = {}
|
|
if (subscription.planCode !== recurlySubscription.plan.plan_code) {
|
|
mismatchReasons.recurlyPlan = recurlySubscription.plan.plan_code
|
|
mismatchReasons.olPlan = subscription.planCode
|
|
}
|
|
if (recurlySubscription.state === 'expired') {
|
|
mismatchReasons.state = 'expired'
|
|
}
|
|
|
|
if (!Object.keys(mismatchReasons).length) {
|
|
return
|
|
}
|
|
|
|
ScriptLogger.mismatchSubscriptionsCount += 1
|
|
const mismatchReasonsString = JSON.stringify(mismatchReasons)
|
|
if (ScriptLogger.allMismatchReasons[mismatchReasonsString]) {
|
|
ScriptLogger.allMismatchReasons[mismatchReasonsString].push({
|
|
id: subscription._id,
|
|
name: subscription.planCode,
|
|
})
|
|
} else {
|
|
ScriptLogger.allMismatchReasons[mismatchReasonsString] = [
|
|
{
|
|
id: subscription._id,
|
|
name: subscription.planCode,
|
|
},
|
|
]
|
|
}
|
|
},
|
|
|
|
printProgress: () => {
|
|
console.warn(
|
|
`Subscriptions checked: ${ScriptLogger.checkedSubscriptionsCount}. Mismatches: ${ScriptLogger.mismatchSubscriptionsCount}`
|
|
)
|
|
},
|
|
|
|
printSummary: () => {
|
|
console.log('All Mismatch Reasons:', ScriptLogger.allMismatchReasons)
|
|
console.log(
|
|
'Mismatch Subscriptions Count',
|
|
ScriptLogger.mismatchSubscriptionsCount
|
|
)
|
|
},
|
|
}
|
|
|
|
const handleSyncSubscriptionError = async (subscription, error) => {
|
|
console.warn(`Errors with subscription id=${subscription._id}:`, error)
|
|
if (typeof error === 'string' && error.match(/429$/)) {
|
|
await setTimeout(1000 * 60 * 5)
|
|
return
|
|
}
|
|
if (typeof error === 'string' && error.match(/5\d\d$/)) {
|
|
await setTimeout(1000 * 60)
|
|
await syncSubscription(subscription)
|
|
return
|
|
}
|
|
await setTimeout(80)
|
|
}
|
|
|
|
const syncSubscription = async subscription => {
|
|
let recurlySubscription
|
|
try {
|
|
recurlySubscription = await RecurlyWrapper.promises.getSubscription(
|
|
subscription.recurlySubscription_id
|
|
)
|
|
} catch (error) {
|
|
await handleSyncSubscriptionError(subscription, error)
|
|
return
|
|
}
|
|
|
|
ScriptLogger.recordMismatch(subscription, recurlySubscription)
|
|
|
|
if (!COMMIT) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
await SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
|
recurlySubscription,
|
|
subscription,
|
|
{}
|
|
)
|
|
} catch (error) {
|
|
await handleSyncSubscriptionError(subscription, error)
|
|
return
|
|
}
|
|
await setTimeout(80)
|
|
}
|
|
|
|
const syncSubscriptions = async subscriptions => {
|
|
const limit = pLimit(ASYNC_LIMIT)
|
|
return await Promise.all(
|
|
subscriptions.map(subscription =>
|
|
limit(() => syncSubscription(subscription))
|
|
)
|
|
)
|
|
}
|
|
|
|
const loopForSubscriptions = async skipInitial => {
|
|
let skip = skipInitial
|
|
|
|
// iterate while there are more subscriptions to fetch
|
|
while (true) {
|
|
const subscriptions = await Subscription.find({
|
|
recurlySubscription_id: { $exists: true, $ne: '' },
|
|
})
|
|
.sort('_id')
|
|
.skip(skip)
|
|
.limit(FETCH_LIMIT)
|
|
.exec()
|
|
|
|
if (subscriptions.length === 0) {
|
|
console.warn('DONE')
|
|
return
|
|
}
|
|
|
|
await syncSubscriptions(subscriptions)
|
|
|
|
ScriptLogger.checkedSubscriptionsCount += subscriptions.length
|
|
retryCounter = 0
|
|
ScriptLogger.printProgress()
|
|
ScriptLogger.printSummary()
|
|
|
|
skip += FETCH_LIMIT
|
|
}
|
|
}
|
|
|
|
let retryCounter = 0
|
|
const run = async () => {
|
|
while (true) {
|
|
try {
|
|
await loopForSubscriptions(
|
|
MONGO_SKIP + ScriptLogger.checkedSubscriptionsCount
|
|
)
|
|
break
|
|
} catch (error) {
|
|
if (retryCounter < 3) {
|
|
console.error(error)
|
|
retryCounter += 1
|
|
console.warn(`RETRYING IN 60 SECONDS. (${retryCounter}/3)`)
|
|
await setTimeout(60000)
|
|
} else {
|
|
console.error('Failed after 3 retries')
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let FETCH_LIMIT, ASYNC_LIMIT, COMMIT, MONGO_SKIP
|
|
const setup = () => {
|
|
const argv = minimist(process.argv.slice(2))
|
|
FETCH_LIMIT = argv.fetch ? argv.fetch : 100
|
|
ASYNC_LIMIT = argv.async ? argv.async : 10
|
|
MONGO_SKIP = argv.skip ? argv.skip : 0
|
|
COMMIT = argv.commit !== undefined
|
|
if (!COMMIT) {
|
|
console.warn('Doing dry run without --commit')
|
|
}
|
|
if (MONGO_SKIP) {
|
|
console.warn(`Skipping first ${MONGO_SKIP} records`)
|
|
}
|
|
}
|
|
|
|
setup()
|
|
await run()
|
|
process.exit()
|