[project-history] return status "423 Locked" when redis lock is taken (#34429)

GitOrigin-RevId: f40230bc98e8ed8a5358e6db5c515cb2a58f9b85
This commit is contained in:
Jakob Ackermann
2026-06-16 08:06:38 +00:00
committed by Copybot
parent b11027d58f
commit cb9e834a1f
2 changed files with 27 additions and 0 deletions
@@ -1,5 +1,6 @@
import Metrics from '@overleaf/metrics'
import logger from '@overleaf/logger'
import OError from '@overleaf/o-error'
import express from 'express'
import bodyParser from 'body-parser'
import * as Errors from './Errors.js'
@@ -54,6 +55,13 @@ app.use(function (error, req, res, next) {
res.sendStatus(422)
} else if (error instanceof Errors.TooManyRequestsError) {
res.status(429).set('Retry-After', 300).end()
} else if (
error instanceof OError &&
error.message === 'Timeout' &&
error.info?.key
) {
logger.warn({ error, req }, error.message)
res.status(423).json({ message: 'redis lock is taken' })
} else {
logger.error({ err: error, req }, error.message)
res.status(500).json({ message: 'an internal error occurred' })
@@ -3,10 +3,13 @@ import { expect } from 'chai'
import { fetchNothing, fetchJsonWithResponse } from '@overleaf/fetch-utils'
import assert from 'node:assert'
import mongodb from 'mongodb-legacy'
import RedisWrapper from '@overleaf/redis-wrapper'
import * as ProjectHistoryClient from './helpers/ProjectHistoryClient.js'
import * as ProjectHistoryApp from './helpers/ProjectHistoryApp.js'
import Settings from '@overleaf/settings'
const { ObjectId } = mongodb
const LockKey = Settings.redis.lock.key_schema
const lockRClient = RedisWrapper.createClient(Settings.redis.lock)
const MockHistoryStore = () => nock('http://127.0.0.1:3100')
const MockWeb = () => nock('http://127.0.0.1:3000')
@@ -150,6 +153,22 @@ describe('Flushing old queues', function () {
})
})
describe('when the project lock is already held', function () {
it('returns 423', async function () {
const key = LockKey.projectHistoryLock({ project_id: this.projectId })
await lockRClient.set(key, 'taken')
try {
const { statusCode } = await ProjectHistoryClient.flushProject(
this.projectId,
{ allowErrors: true }
)
expect(statusCode).to.equal(423)
} finally {
await lockRClient.del(key)
}
})
})
describe('when the update is newer than the cutoff and project has short queue', function () {
beforeEach(function () {
Settings.shortHistoryQueues.push(this.projectId)