fix_docs_with_empty_pathnames.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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 util = require('node:util')
  10. const flushAndDeleteDocWithLock = util.promisify(
  11. DocumentManager.flushAndDeleteDocWithLock
  12. )
  13. async function flushAndDeleteDocs(dockeys, options) {
  14. const docIds = ProjectFlusher._extractIds(dockeys)
  15. for (const docId of docIds) {
  16. const pathname = await rclient.get(keys.pathname({ doc_id: docId }))
  17. if (!pathname) {
  18. const projectId = await rclient.get(keys.projectKey({ doc_id: docId }))
  19. if (!projectId) {
  20. // await deleteDanglingDoc(projectId, docId, pathname, options)
  21. logger.info(
  22. { projectId, docId, pathname },
  23. 'skipping doc with empty pathname and project id'
  24. )
  25. } else {
  26. await flushAndDeleteDoc(projectId, docId, pathname, options)
  27. }
  28. }
  29. }
  30. }
  31. async function flushAndDeleteDoc(projectId, docId, pathname, options) {
  32. if (options.dryRun) {
  33. logger.info(
  34. { projectId, docId, pathname },
  35. 'dry run mode - would flush doc with empty pathname'
  36. )
  37. return
  38. }
  39. logger.info(
  40. { projectId, docId, pathname },
  41. 'flushing doc with empty pathname'
  42. )
  43. try {
  44. await flushAndDeleteDocWithLock(projectId, docId, {})
  45. } catch (err) {
  46. logger.error(
  47. { projectId, docId, pathname, err },
  48. 'error flushing and deleting doc without pathname'
  49. )
  50. }
  51. }
  52. async function cleanUpDocs(options) {
  53. logger.info({ options }, 'cleaning up docs without pathnames')
  54. let cursor = 0
  55. do {
  56. const [newCursor, doclinesKeys] = await rclient.scan(
  57. cursor,
  58. 'MATCH',
  59. keys.docLines({ doc_id: '*' }),
  60. 'COUNT',
  61. options.limit
  62. )
  63. await flushAndDeleteDocs(doclinesKeys, options)
  64. cursor = newCursor
  65. } while (cursor !== '0')
  66. }
  67. cleanUpDocs({ limit: 1000, dryRun: process.env.DRY_RUN !== 'false' })
  68. .then(result => {
  69. rclient.quit()
  70. console.log('DONE')
  71. })
  72. .catch(function (error) {
  73. console.error(error)
  74. process.exit(1)
  75. })