fix_docs_with_missing_project.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. const Settings = require('@overleaf/settings')
  2. const logger = require('@overleaf/logger')
  3. const rclient = require('@overleaf/redis-wrapper').createClient(
  4. Settings.redis.documentupdater
  5. )
  6. const keys = Settings.redis.documentupdater.key_schema
  7. const ProjectFlusher = require('../app/js/ProjectFlusher')
  8. const DocumentManager = require('../app/js/DocumentManager')
  9. const { mongoClient, db, ObjectId } = require('../app/js/mongodb')
  10. const util = require('node:util')
  11. const flushAndDeleteDocWithLock = util.promisify(
  12. DocumentManager.flushAndDeleteDocWithLock
  13. )
  14. async function fixDocsWithMissingProjectIds(dockeys, options) {
  15. const docIds = ProjectFlusher._extractIds(dockeys)
  16. for (const docId of docIds) {
  17. const projectId = await rclient.get(keys.projectKey({ doc_id: docId }))
  18. logger.debug({ docId, projectId }, 'checking doc')
  19. if (!projectId) {
  20. try {
  21. await insertMissingProjectId(docId, options)
  22. } catch (err) {
  23. logger.error({ docId, err }, 'error fixing doc without project id')
  24. }
  25. }
  26. }
  27. }
  28. async function insertMissingProjectId(docId, options) {
  29. const doc = await db.docs.findOne({ _id: ObjectId(docId) })
  30. if (!doc) {
  31. logger.warn({ docId }, 'doc not found in mongo')
  32. return
  33. }
  34. if (!doc.project_id) {
  35. logger.error({ docId }, 'doc does not have project id in mongo')
  36. return
  37. }
  38. logger.debug({ docId, doc }, 'found doc')
  39. const projectIdFromMongo = doc.project_id.toString()
  40. if (options.dryRun) {
  41. logger.info(
  42. { projectIdFromMongo, docId },
  43. 'dry run mode - would insert project id in redis'
  44. )
  45. return
  46. }
  47. // set the project id for this doc
  48. await rclient.set(keys.projectKey({ doc_id: docId }), projectIdFromMongo)
  49. logger.debug({ docId, projectIdFromMongo }, 'inserted project id in redis')
  50. if (projectIdFromMongo) {
  51. await flushAndDeleteDocWithLock(projectIdFromMongo, docId, {})
  52. logger.info(
  53. { docId, projectIdFromMongo },
  54. 'fixed doc with empty project id'
  55. )
  56. }
  57. return projectIdFromMongo
  58. }
  59. async function findAndProcessDocs(options) {
  60. logger.info({ options }, 'fixing docs with missing projcct id')
  61. let cursor = 0
  62. do {
  63. const [newCursor, doclinesKeys] = await rclient.scan(
  64. cursor,
  65. 'MATCH',
  66. keys.docLines({ doc_id: '*' }),
  67. 'COUNT',
  68. options.limit
  69. )
  70. await fixDocsWithMissingProjectIds(doclinesKeys, options)
  71. cursor = newCursor
  72. } while (cursor !== '0')
  73. }
  74. findAndProcessDocs({ limit: 1000, dryRun: process.env.DRY_RUN !== 'false' })
  75. .then(result => {
  76. rclient.quit()
  77. mongoClient.close()
  78. console.log('DONE')
  79. })
  80. .catch(function (error) {
  81. console.error(error)
  82. process.exit(1)
  83. })