mirror of
https://github.com/overleaf/overleaf.git
synced 2025-02-23 10:03:56 +00:00
Merge pull request #19273 from overleaf/em-history-migration-concurrency
Add concurrency option to history ranges support migration script GitOrigin-RevId: 8707abc9b76116090332b6abb11030adb17ceb4e
This commit is contained in:
parent
934151106e
commit
fbdf245517
2 changed files with 82 additions and 37 deletions
|
@ -26,6 +26,7 @@ const {
|
|||
* @param {boolean} [opts.force]
|
||||
* @param {boolean} [opts.stopOnError]
|
||||
* @param {boolean} [opts.quickOnly]
|
||||
* @param {number} [opts.concurrency]
|
||||
*/
|
||||
async function migrateProjects(opts = {}) {
|
||||
const {
|
||||
|
@ -38,6 +39,7 @@ async function migrateProjects(opts = {}) {
|
|||
force = false,
|
||||
stopOnError = false,
|
||||
quickOnly = false,
|
||||
concurrency = 1,
|
||||
} = opts
|
||||
|
||||
const clauses = []
|
||||
|
@ -70,11 +72,31 @@ async function migrateProjects(opts = {}) {
|
|||
})
|
||||
.sort({ _id: -1 })
|
||||
|
||||
let terminating = false
|
||||
const handleSignal = signal => {
|
||||
logger.info({ signal }, 'History ranges support migration received signal')
|
||||
terminating = true
|
||||
}
|
||||
process.on('SIGINT', handleSignal)
|
||||
process.on('SIGTERM', handleSignal)
|
||||
|
||||
let projectsProcessed = 0
|
||||
const jobsByProjectId = new Map()
|
||||
let errors = 0
|
||||
|
||||
for await (const project of projects) {
|
||||
if (projectsProcessed >= maxCount) {
|
||||
break
|
||||
}
|
||||
|
||||
if (errors > 0 && stopOnError) {
|
||||
break
|
||||
}
|
||||
|
||||
if (terminating) {
|
||||
break
|
||||
}
|
||||
|
||||
const projectId = project._id.toString()
|
||||
|
||||
if (!force) {
|
||||
|
@ -89,45 +111,63 @@ async function migrateProjects(opts = {}) {
|
|||
}
|
||||
}
|
||||
|
||||
const startTimeMs = Date.now()
|
||||
let quickMigrationSuccess
|
||||
try {
|
||||
quickMigrationSuccess = await quickMigration(projectId, direction)
|
||||
if (!quickMigrationSuccess) {
|
||||
if (quickOnly) {
|
||||
logger.info(
|
||||
{ projectId, direction },
|
||||
'Quick migration failed, skipping project'
|
||||
)
|
||||
} else {
|
||||
await migrateProject(projectId, direction)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
{ err, projectId, direction, projectsProcessed },
|
||||
'Failed to migrate history ranges support'
|
||||
)
|
||||
projectsProcessed += 1
|
||||
if (stopOnError) {
|
||||
break
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if (jobsByProjectId.size >= concurrency) {
|
||||
// Wait until the next job finishes
|
||||
await Promise.race(jobsByProjectId.values())
|
||||
}
|
||||
const elapsedMs = Date.now() - startTimeMs
|
||||
projectsProcessed += 1
|
||||
logger.info(
|
||||
{
|
||||
projectId,
|
||||
direction,
|
||||
projectsProcessed,
|
||||
elapsedMs,
|
||||
quick: quickMigrationSuccess,
|
||||
},
|
||||
'Migrated history ranges support'
|
||||
)
|
||||
|
||||
const job = processProject(projectId, direction, quickOnly)
|
||||
.then(info => {
|
||||
jobsByProjectId.delete(projectId)
|
||||
projectsProcessed += 1
|
||||
logger.info(
|
||||
{
|
||||
projectId,
|
||||
direction,
|
||||
projectsProcessed,
|
||||
errors,
|
||||
...info,
|
||||
},
|
||||
'History ranges support migration'
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
jobsByProjectId.delete(projectId)
|
||||
errors += 1
|
||||
logger.error(
|
||||
{ err, projectId, direction, projectsProcessed, errors },
|
||||
'Failed to migrate history ranges support'
|
||||
)
|
||||
})
|
||||
|
||||
jobsByProjectId.set(projectId, job)
|
||||
}
|
||||
|
||||
// Let the last jobs finish
|
||||
await Promise.all(jobsByProjectId.values())
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a single project
|
||||
*
|
||||
* @param {string} projectId
|
||||
* @param {"forwards" | "backwards"} direction
|
||||
* @param {boolean} quickOnly
|
||||
*/
|
||||
async function processProject(projectId, direction, quickOnly) {
|
||||
const startTimeMs = Date.now()
|
||||
const quickMigrationSuccess = await quickMigration(projectId, direction)
|
||||
let migrationType
|
||||
if (quickMigrationSuccess) {
|
||||
migrationType = 'quick'
|
||||
} else if (quickOnly) {
|
||||
migrationType = 'skipped'
|
||||
} else {
|
||||
await migrateProject(projectId, direction)
|
||||
migrationType = 'resync'
|
||||
}
|
||||
const elapsedMs = Date.now() - startTimeMs
|
||||
return { migrationType, elapsedMs }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,7 @@ async function main() {
|
|||
force,
|
||||
stopOnError,
|
||||
quickOnly,
|
||||
concurrency,
|
||||
} = parseArgs()
|
||||
await HistoryRangesSupportMigration.promises.migrateProjects({
|
||||
projectIds,
|
||||
|
@ -25,6 +26,7 @@ async function main() {
|
|||
force,
|
||||
stopOnError,
|
||||
quickOnly,
|
||||
concurrency,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -44,6 +46,7 @@ Options:
|
|||
--force Migrate projects even if they were already migrated
|
||||
--stop-on-error Stop after first migration error
|
||||
--quick-only Do not try a resync migration if quick migration fails
|
||||
--concurrency How many jobs to run in parallel
|
||||
`)
|
||||
}
|
||||
|
||||
|
@ -67,6 +70,7 @@ function parseArgs() {
|
|||
const force = args.force
|
||||
const stopOnError = args['stop-on-error']
|
||||
const quickOnly = args['quick-only']
|
||||
const concurrency = args.concurrency ?? 1
|
||||
const all = args.all
|
||||
|
||||
if (
|
||||
|
@ -94,6 +98,7 @@ function parseArgs() {
|
|||
force,
|
||||
stopOnError,
|
||||
quickOnly,
|
||||
concurrency,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue