Pārlūkot izejas kodu

Merge pull request #8787 from overleaf/msm-force-doc-flush

[web] script to force flushing docs to mongo

GitOrigin-RevId: 6ce3c1e456b92610fe4f90993b373db2070ab392
June Kelly 4 gadi atpakaļ
vecāks
revīzija
34a7d3598f

+ 12 - 3
services/web/app/src/Features/DocumentUpdater/DocumentUpdaterHandler.js

@@ -81,11 +81,20 @@ function flushDocToMongo(projectId, docId, callback) {
   )
 }
 
-function deleteDoc(projectId, docId, callback) {
+function deleteDoc(projectId, docId, ignoreFlushErrors, callback) {
+  if (typeof ignoreFlushErrors === 'function') {
+    callback = ignoreFlushErrors
+    ignoreFlushErrors = false
+  }
+  let path = `/project/${projectId}/doc/${docId}`
+  if (ignoreFlushErrors) {
+    path += '?ignore_flush_errors=true'
+  }
+  const method = 'DELETE'
   _makeRequest(
     {
-      path: `/project/${projectId}/doc/${docId}`,
-      method: 'DELETE',
+      path,
+      method,
     },
     projectId,
     'delete.mongo.doc',

+ 74 - 0
services/web/scripts/force_doc_flush.js

@@ -0,0 +1,74 @@
+const { ObjectId } = require('mongodb')
+const { db, waitForDb } = require('../app/src/infrastructure/mongodb')
+const DocumentUpdaterHandler = require('../app/src/Features/DocumentUpdater/DocumentUpdaterHandler')
+
+const PROJECT_ID = process.env.PROJECT_ID
+const DOC_ID = process.env.DOC_ID
+const VERBOSE_LOGGING = process.env.VERBOSE_LOGGING === 'true'
+const DRY_RUN = process.env.DRY_RUN !== 'false'
+
+console.log({
+  PROJECT_ID,
+  DOC_ID,
+  VERBOSE_LOGGING,
+  DRY_RUN,
+})
+
+async function main() {
+  await waitForDb()
+
+  const { lines, version, ranges } = await getDocument()
+  const size = lines.reduce((size, line) => size + line.length + 1, 0)
+
+  console.log('doc stats:', {
+    lineCount: lines.length,
+    size,
+    version,
+  })
+  if (!DRY_RUN) {
+    console.log(`updating doc ${DOC_ID} in mongo for project ${PROJECT_ID}`)
+    const { result } = await db.docs.updateOne(
+      { _id: ObjectId(DOC_ID), project_id: ObjectId(PROJECT_ID) },
+      {
+        $set: { lines, version, ranges },
+        $inc: { rev: 1 }, // maintain same behaviour as Docstore upsertIntoDocCollection
+        $unset: {
+          inS3: true,
+        },
+      }
+    )
+    console.log('mongo result', result)
+    if (result.n !== 1 || result.nModified !== 1 || result.ok !== 1) {
+      throw new Error('unexpected result from mongo update')
+    }
+    console.log(`deleting doc ${DOC_ID} from redis for project ${PROJECT_ID}`)
+    await DocumentUpdaterHandler.promises.deleteDoc(PROJECT_ID, DOC_ID, true)
+  }
+}
+
+function getDocument() {
+  return new Promise((resolve, reject) => {
+    DocumentUpdaterHandler.getDocument(
+      PROJECT_ID,
+      DOC_ID,
+      -1,
+      (error, lines, version, ranges) => {
+        if (error) {
+          reject(error)
+        } else {
+          resolve({ lines, version, ranges })
+        }
+      }
+    )
+  })
+}
+
+main()
+  .then(() => {
+    console.error('Done.')
+    process.exit(0)
+  })
+  .catch(error => {
+    console.error({ error })
+    process.exit(1)
+  })

+ 36 - 0
services/web/test/unit/src/DocumentUpdater/DocumentUpdaterHandlerTests.js

@@ -320,6 +320,42 @@ describe('DocumentUpdaterHandler', function () {
           .should.equal(true)
       })
     })
+
+    describe("with 'ignoreFlushErrors' option", function () {
+      beforeEach(function () {
+        this.request.callsArgWith(1, null, { statusCode: 204 }, '')
+      })
+
+      it('when option is true, should send a `ignore_flush_errors=true` URL query to document-updater', function () {
+        this.handler.deleteDoc(
+          this.project_id,
+          this.doc_id,
+          true,
+          this.callback
+        )
+        this.request
+          .calledWithMatch({
+            url: `${this.settings.apis.documentupdater.url}/project/${this.project_id}/doc/${this.doc_id}?ignore_flush_errors=true`,
+            method: 'DELETE',
+          })
+          .should.equal(true)
+      })
+
+      it("when option is false, shouldn't send any URL query to document-updater", function () {
+        this.handler.deleteDoc(
+          this.project_id,
+          this.doc_id,
+          false,
+          this.callback
+        )
+        this.request
+          .calledWithMatch({
+            url: `${this.settings.apis.documentupdater.url}/project/${this.project_id}/doc/${this.doc_id}`,
+            method: 'DELETE',
+          })
+          .should.equal(true)
+      })
+    })
   })
 
   describe('setDocument', function () {