Merge pull request #26477 from overleaf/em-redis-buffer-resync

Handle invalid content hash when persisting changes

GitOrigin-RevId: 5259190396c8c261cad1abcd5de66314c1e871fb
This commit is contained in:
Eric Mc Sween
2025-06-17 10:07:29 -04:00
committed by Copybot
parent 5e556ba89d
commit 847db0b056
6 changed files with 43 additions and 1 deletions
@@ -163,6 +163,7 @@ async function flushChanges(req, res, next) {
maxChanges: 0,
minChangeTimestamp: farFuture,
maxChangeTimestamp: farFuture,
autoResync: true,
}
try {
await persistBuffer(projectId, limits)
@@ -104,5 +104,9 @@
"password": "REDIS_PASSWORD",
"port": "REDIS_PORT"
}
},
"projectHistory": {
"host": "PROJECT_HISTORY_HOST",
"port": "PROJECT_HISTORY_PORT"
}
}
+4 -1
View File
@@ -39,5 +39,8 @@
"databasePoolMin": "2",
"databasePoolMax": "10",
"httpsOnly": "false",
"httpRequestTimeout": "300000"
"httpRequestTimeout": "300000",
"projectHistory": {
"port": "3054"
}
}
@@ -9,6 +9,7 @@ const chunkStore = require('./chunk_store')
const { BlobStore } = require('./blob_store')
const BatchBlobStore = require('./batch_blob_store')
const persistChanges = require('./persist_changes')
const resyncProject = require('./resync_project')
const redisBackend = require('./chunk_store/redis')
/**
@@ -171,6 +172,24 @@ async function persistBuffer(projectId, limits) {
'updated persisted version in Redis'
)
// 7. Resync the project if content hash validation failed
if (limits.autoResync && persistResult.resyncNeeded) {
if (
changesToPersist.some(
change => change.getOrigin()?.getKind() === 'history-resync'
)
) {
// To avoid an infinite loop, do not resync if the current batch of
// changes contains a history resync.
logger.warn(
{ projectId },
'content hash validation failed while persisting a history resync, skipping additional resync'
)
} else {
await resyncProject(projectId)
}
}
logger.debug(
{ projectId, finalPersistedVersion: newEndVersion },
'persistBuffer operation completed successfully'
@@ -0,0 +1,14 @@
// @ts-check
const config = require('config')
const { fetchNothing } = require('@overleaf/fetch-utils')
const PROJECT_HISTORY_URL = `http://${config.projectHistory.host}:${config.projectHistory.port}`
async function resyncProject(projectId) {
await fetchNothing(`${PROJECT_HISTORY_URL}/project/${projectId}/resync`, {
method: 'POST',
})
}
module.exports = resyncProject
@@ -45,6 +45,7 @@ async function persistProjectAction(projectId) {
maxChanges: 0,
minChangeTimestamp: farFuture,
maxChangeTimestamp: farFuture,
autoResync: true,
}
await persistBuffer(projectId, limits)
if (job && job.close) {