delete_docs_with_empty_pathnames.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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 RedisManager = require('app/js/RedisManager')
  10. const util = require('util')
  11. const flushAndDeleteDocWithLock = util.promisify(
  12. DocumentManager.flushAndDeleteDocWithLock
  13. )
  14. // const getDoc = util.promisify((projectId, docId, cb) => {
  15. // RedisManager.getDoc(projectId, docId, (err, ...results) => {
  16. // cb(err, results)
  17. // })
  18. // })
  19. // const removeDocFromMemory = util.promisify(RedisManager.removeDocFromMemory)
  20. async function flushAndDeleteDocs(dockeys, options) {
  21. logger.debug({ dockeys }, 'trying keys')
  22. const docIds = ProjectFlusher._extractIds(dockeys)
  23. for (const docId of docIds) {
  24. const pathname = await rclient.get(keys.pathname({ doc_id: docId }))
  25. logger.debug({ docId, pathname }, 'checking doc')
  26. if (!pathname) {
  27. const projectId = await rclient.get(keys.projectKey({ doc_id: docId }))
  28. if (!projectId) {
  29. // await deleteDanglingDoc(projectId, docId, pathname, options)
  30. logger.info(
  31. { projectId, docId, pathname },
  32. 'skipping doc with empty pathname and project id'
  33. )
  34. } else {
  35. await flushAndDeleteDoc(projectId, docId, pathname, options)
  36. }
  37. }
  38. }
  39. }
  40. // async function deleteDanglingDoc(projectId, docId, pathname, options) {
  41. // const [
  42. // // eslint-disable-next-line no-unused-vars
  43. // _docLines,
  44. // version,
  45. // // eslint-disable-next-line no-unused-vars
  46. // _ranges,
  47. // // eslint-disable-next-line no-unused-vars
  48. // _pathname,
  49. // projectHistoryId,
  50. // unflushedTime,
  51. // lastUpdatedAt,
  52. // lastUpdatedBy,
  53. // ] = await getDoc(projectId, docId)
  54. // logger.warn(
  55. // {
  56. // projectId,
  57. // docId,
  58. // pathname,
  59. // version,
  60. // projectHistoryId,
  61. // unflushedTime,
  62. // lastUpdatedAt,
  63. // lastUpdatedBy,
  64. // },
  65. // 'missing project id'
  66. // )
  67. // if (options.dryRun) {
  68. // logger.info(
  69. // { projectId, docId, pathname },
  70. // 'dry run mode - would delete doc with empty pathname and project id'
  71. // )
  72. // return
  73. // }
  74. // logger.info(
  75. // { projectId, docId, pathname },
  76. // 'deleting doc with empty pathname and project id'
  77. // )
  78. // try {
  79. // await removeDocFromMemory(projectId, docId)
  80. // } catch (err) {
  81. // logger.error(
  82. // { projectId, docId, pathname, err },
  83. // 'error deleting doc with empty pathname and project id'
  84. // )
  85. // }
  86. // }
  87. async function flushAndDeleteDoc(projectId, docId, pathname, options) {
  88. if (options.dryRun) {
  89. logger.info(
  90. { projectId, docId, pathname },
  91. 'dry run mode - would flush doc with empty pathname'
  92. )
  93. return
  94. }
  95. logger.info(
  96. { projectId, docId, pathname },
  97. 'flushing doc with empty pathname'
  98. )
  99. try {
  100. await flushAndDeleteDocWithLock(projectId, docId, {})
  101. } catch (err) {
  102. logger.error(
  103. { projectId, docId, pathname, err },
  104. 'error flushing and deleting doc without pathname'
  105. )
  106. }
  107. }
  108. async function cleanUpDocs(options) {
  109. logger.info({ options }, 'cleaning up docs without pathnames')
  110. let cursor = 0
  111. do {
  112. const [newCursor, doclinesKeys] = await rclient.scan(
  113. cursor,
  114. 'MATCH',
  115. keys.docLines({ doc_id: '*' }),
  116. 'COUNT',
  117. options.limit
  118. )
  119. logger.debug({ count: doclinesKeys.length }, 'found docs')
  120. await flushAndDeleteDocs(doclinesKeys, options)
  121. cursor = newCursor
  122. } while (cursor !== '0')
  123. }
  124. cleanUpDocs({ limit: 1000, dryRun: true })
  125. .then(result => {
  126. console.log('DONE')
  127. })
  128. .catch(function (error) {
  129. if (error) {
  130. throw error
  131. }
  132. return process.exit()
  133. })