mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
[web] shard compile server persistence by compileBackendClass (#29156)
* [web] shard compile server persistence by compileBackendClass * [web] make prettier happy GitOrigin-RevId: d7cf8bde07e7110053d9d7531c007111af5cc46b
This commit is contained in:
@@ -20,7 +20,21 @@ if (Settings.redis.clsi_cookie_secondary != null) {
|
||||
}
|
||||
|
||||
const ClsiCookieManagerFactory = function (backendGroup) {
|
||||
function buildKey(projectId, userId) {
|
||||
/**
|
||||
* @param {string} projectId
|
||||
* @param {string | null} userId
|
||||
* @param {string} compileBackendClass
|
||||
* @return {string}
|
||||
*/
|
||||
function buildKey(projectId, userId, compileBackendClass) {
|
||||
if (backendGroup != null) {
|
||||
return `clsiserver:${backendGroup}:${compileBackendClass}:${projectId}:${userId}`
|
||||
} else {
|
||||
return `clsiserver:${compileBackendClass}:${projectId}:${userId}`
|
||||
}
|
||||
}
|
||||
|
||||
function buildOldKey(projectId, userId) {
|
||||
if (backendGroup != null) {
|
||||
return `clsiserver:${backendGroup}:${projectId}:${userId}`
|
||||
} else {
|
||||
@@ -37,7 +51,14 @@ const ClsiCookieManagerFactory = function (backendGroup) {
|
||||
if (!clsiCookiesEnabled) {
|
||||
return
|
||||
}
|
||||
const serverId = await rclient.get(buildKey(projectId, userId))
|
||||
let serverId = await rclient.get(
|
||||
buildKey(projectId, userId, compileBackendClass)
|
||||
)
|
||||
if (!serverId) {
|
||||
// Fallback to the old key.
|
||||
// TODO(das7pad): remove this in 24h.
|
||||
serverId = await rclient.get(buildOldKey(projectId, userId))
|
||||
}
|
||||
|
||||
if (!serverId) {
|
||||
return await cookieManager.promises._populateServerIdViaRequest(
|
||||
@@ -157,7 +178,7 @@ const ClsiCookieManagerFactory = function (backendGroup) {
|
||||
if (serverId == null) {
|
||||
// We don't get a cookie back if it hasn't changed
|
||||
return await rclient.expire(
|
||||
buildKey(projectId, userId),
|
||||
buildKey(projectId, userId, compileBackendClass),
|
||||
_getTTLInSeconds(previous)
|
||||
)
|
||||
}
|
||||
@@ -176,15 +197,28 @@ const ClsiCookieManagerFactory = function (backendGroup) {
|
||||
rclientSecondary,
|
||||
projectId,
|
||||
userId,
|
||||
compileBackendClass,
|
||||
serverId
|
||||
).catch(() => {})
|
||||
}
|
||||
await _setServerIdInRedis(rclient, projectId, userId, serverId)
|
||||
await _setServerIdInRedis(
|
||||
rclient,
|
||||
projectId,
|
||||
userId,
|
||||
compileBackendClass,
|
||||
serverId
|
||||
)
|
||||
}
|
||||
|
||||
async function _setServerIdInRedis(rclient, projectId, userId, serverId) {
|
||||
async function _setServerIdInRedis(
|
||||
rclient,
|
||||
projectId,
|
||||
userId,
|
||||
compileBackendClass,
|
||||
serverId
|
||||
) {
|
||||
await rclient.setex(
|
||||
buildKey(projectId, userId),
|
||||
buildKey(projectId, userId, compileBackendClass),
|
||||
_getTTLInSeconds(serverId),
|
||||
serverId
|
||||
)
|
||||
|
||||
@@ -38,13 +38,53 @@ const CLSI_COOKIES_ENABLED = (Settings.clsiCookie?.key ?? '') !== ''
|
||||
// The timeout in services/clsi/app.js is 10 minutes, so we'll be on the safe side with 12 minutes
|
||||
const COMPILE_REQUEST_TIMEOUT_MS = 12 * 60 * 1000
|
||||
|
||||
async function clearClsiServerId(projectId, userId) {
|
||||
const jobs = [ClsiCookieManager.promises.clearServerId(projectId, userId)]
|
||||
function getNewCompileBackendClass(projectId, compileBackendClass) {
|
||||
// Sample x% of projects to move up one bracket.
|
||||
if (
|
||||
SplitTestHandler.getPercentile(projectId, 'double-compile', 'release') >=
|
||||
Settings.apis.clsi_new.sample
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
switch (compileBackendClass) {
|
||||
case 'n2d':
|
||||
return 'n4'
|
||||
case 'c2d':
|
||||
return 'n4'
|
||||
default:
|
||||
throw new Error('unknown ?compileBackendClass')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} projectId
|
||||
* @param {string | null} userId
|
||||
* @param {string} compileBackendClass
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function clearClsiServerId(projectId, userId, compileBackendClass) {
|
||||
const jobs = [
|
||||
ClsiCookieManager.promises.clearServerId(
|
||||
projectId,
|
||||
userId,
|
||||
compileBackendClass
|
||||
),
|
||||
]
|
||||
if (Settings.apis.clsi_new?.url) {
|
||||
// Mirror resetting the clsiserverid in both backends.
|
||||
jobs.push(
|
||||
NewBackendCloudClsiCookieManager.promises.clearServerId(projectId, userId)
|
||||
const newCompileBackendClass = getNewCompileBackendClass(
|
||||
projectId,
|
||||
compileBackendClass
|
||||
)
|
||||
if (newCompileBackendClass) {
|
||||
jobs.push(
|
||||
NewBackendCloudClsiCookieManager.promises.clearServerId(
|
||||
projectId,
|
||||
userId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
await Promise.all(jobs)
|
||||
}
|
||||
@@ -176,14 +216,14 @@ async function deleteAuxFiles(projectId, userId, options, clsiserverid) {
|
||||
await DocumentUpdaterHandler.promises.clearProjectState(projectId)
|
||||
} finally {
|
||||
// always clear the clsi server id, even if prior actions failed
|
||||
await clearClsiServerId(projectId, userId)
|
||||
await clearClsiServerId(projectId, userId, compileBackendClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function _sendBuiltRequest(projectId, userId, req, options) {
|
||||
if (options.forceNewClsiServer) {
|
||||
await clearClsiServerId(projectId, userId)
|
||||
await clearClsiServerId(projectId, userId, options.compileBackendClass)
|
||||
}
|
||||
const validationProblems = ClsiFormatChecker.checkRecoursesForProblems(
|
||||
req.compile?.resources
|
||||
@@ -436,28 +476,15 @@ async function _makeNewBackendRequest(
|
||||
if (Settings.apis.clsi_new?.url == null) {
|
||||
return null
|
||||
}
|
||||
const newCompileBackendClass = getNewCompileBackendClass(
|
||||
projectId,
|
||||
currentCompileBackendClass
|
||||
)
|
||||
if (!newCompileBackendClass) return null
|
||||
|
||||
url = new URL(
|
||||
url.toString().replace(Settings.apis.clsi.url, Settings.apis.clsi_new.url)
|
||||
)
|
||||
|
||||
// Sample x% of projects to move up one bracket.
|
||||
if (
|
||||
SplitTestHandler.getPercentile(projectId, 'double-compile', 'release') >=
|
||||
Settings.apis.clsi_new.sample
|
||||
)
|
||||
return null
|
||||
|
||||
let newCompileBackendClass
|
||||
switch (currentCompileBackendClass) {
|
||||
case 'n2d':
|
||||
newCompileBackendClass = 'n4'
|
||||
break
|
||||
case 'c2d':
|
||||
newCompileBackendClass = 'n4'
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown ?compileBackendClass')
|
||||
}
|
||||
url.searchParams.set('compileBackendClass', newCompileBackendClass)
|
||||
|
||||
const clsiServerId =
|
||||
|
||||
@@ -54,6 +54,28 @@ describe('ClsiCookieManager', function () {
|
||||
'',
|
||||
'n2d'
|
||||
)
|
||||
this.redis.get
|
||||
.calledWith(`clsiserver:n2d:${this.project_id}:${this.user_id}`)
|
||||
.should.equal(true)
|
||||
serverId.should.equal('clsi-7')
|
||||
})
|
||||
|
||||
it('should fallback to old key', async function () {
|
||||
this.redis.get
|
||||
.withArgs(`clsiserver:n2d:${this.project_id}:${this.user_id}`)
|
||||
.resolves(null)
|
||||
this.redis.get
|
||||
.withArgs(`clsiserver:${this.project_id}:${this.user_id}`)
|
||||
.resolves('clsi-7')
|
||||
const serverId = await this.ClsiCookieManager.promises.getServerId(
|
||||
this.project_id,
|
||||
this.user_id,
|
||||
'',
|
||||
'n2d'
|
||||
)
|
||||
this.redis.get
|
||||
.calledWith(`clsiserver:n2d:${this.project_id}:${this.user_id}`)
|
||||
.should.equal(true)
|
||||
this.redis.get
|
||||
.calledWith(`clsiserver:${this.project_id}:${this.user_id}`)
|
||||
.should.equal(true)
|
||||
@@ -177,7 +199,7 @@ describe('ClsiCookieManager', function () {
|
||||
null
|
||||
)
|
||||
this.redis.setex.should.have.been.calledWith(
|
||||
`clsiserver:${this.project_id}:${this.user_id}`,
|
||||
`clsiserver:n2d:${this.project_id}:${this.user_id}`,
|
||||
this.settings.clsiCookie.ttlInSeconds,
|
||||
this.clsiServerId
|
||||
)
|
||||
@@ -194,7 +216,7 @@ describe('ClsiCookieManager', function () {
|
||||
null
|
||||
)
|
||||
expect(this.redis.setex).to.have.been.calledWith(
|
||||
`clsiserver:${this.project_id}:${this.user_id}`,
|
||||
`clsiserver:n2d:${this.project_id}:${this.user_id}`,
|
||||
this.settings.clsiCookie.ttlInSecondsRegular,
|
||||
this.clsiServerId
|
||||
)
|
||||
@@ -245,7 +267,7 @@ describe('ClsiCookieManager', function () {
|
||||
null
|
||||
)
|
||||
this.redis_secondary.setex.should.have.been.calledWith(
|
||||
`clsiserver:${this.project_id}:${this.user_id}`,
|
||||
`clsiserver:n2d:${this.project_id}:${this.user_id}`,
|
||||
this.settings.clsiCookie.ttlInSeconds,
|
||||
this.clsiServerId
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user