Merge pull request #14836 from overleaf/ab-split-test-cache-refactoring

[web] Fetch all active split test into cache at once

GitOrigin-RevId: b477b88bf281349433af2cf692a0e9ea5b036588
This commit is contained in:
Alexandre Bourdin 2023-10-16 14:01:16 +02:00 committed by Copybot
parent 719da5fbd8
commit b8a5eca1d0
4 changed files with 60 additions and 33 deletions

View file

@ -9,15 +9,12 @@ class SplitTestCache extends CacheLoader {
})
}
async load(name) {
Metrics.inc('split_test_get_split_test_from_mongo', 1, {
path: name,
})
const splitTest = await SplitTestManager.getSplitTest({
name,
archived: { $ne: true },
})
return splitTest?.toObject()
async load() {
Metrics.inc('split_test_get_split_test_from_mongo', 1, {})
const splitTests = await SplitTestManager.getRuntimeTests()
return new Map(
splitTests.map(splitTest => [splitTest.name, splitTest.toObject()])
)
}
serialize(value) {

View file

@ -225,7 +225,7 @@ async function sessionMaintenance(req, user) {
* @private
*/
async function _getVariantNames(splitTestName) {
const splitTest = await SplitTestCache.get(splitTestName)
const splitTest = await _getSplitTest(splitTestName)
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
if (currentVersion?.active) {
return currentVersion.variants.map(v => v.name).concat([DEFAULT_VARIANT])
@ -242,7 +242,7 @@ async function _getAssignment(
return DEFAULT_ASSIGNMENT
}
const splitTest = await SplitTestCache.get(splitTestName)
const splitTest = await _getSplitTest(splitTestName)
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
if (!currentVersion?.active) {
return DEFAULT_ASSIGNMENT
@ -493,9 +493,14 @@ async function _getUser(id, splitTestName) {
}
async function _loadSplitTestInfoInLocals(locals, splitTestName) {
const splitTest = await SplitTestCache.get(splitTestName)
const splitTest = await _getSplitTest(splitTestName)
if (splitTest) {
const phase = SplitTestUtils.getCurrentVersion(splitTest).phase
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
if (!currentVersion.active) {
return
}
const phase = currentVersion.phase
LocalsHelper.setSplitTestInfo(locals, splitTestName, {
phase,
badgeInfo: splitTest.badgeInfo?.[phase],
@ -538,6 +543,11 @@ function _collectSessionStats(session) {
}
}
async function _getSplitTest(name) {
const splitTests = await SplitTestCache.get('')
return splitTests?.get(name)
}
module.exports = {
getPercentile,
getAssignment: callbackify(getAssignment),

View file

@ -57,6 +57,16 @@ async function getSplitTests({ name, phase, type, active, archived }) {
}
}
async function getRuntimeTests() {
try {
return await SplitTest.find({
archived: { $ne: true },
}).exec()
} catch (error) {
throw OError.tag(error, 'Failed to get active split tests list')
}
}
async function getSplitTest(query) {
try {
return await SplitTest.findOne(query)
@ -439,6 +449,7 @@ function _mergeFlags(incomingTests, baseTests) {
module.exports = {
getSplitTest,
getSplitTests,
getRuntimeTests,
createSplitTest,
updateSplitTestConfig,
updateSplitTestInfo,

View file

@ -22,6 +22,10 @@ describe('SplitTestHandler', function () {
versionNumber: 2,
}),
]
this.cachedSplitTests = new Map()
for (const splitTest of this.splitTests) {
this.cachedSplitTests.set(splitTest.name, splitTest)
}
this.UserGetter = {
promises: {
@ -36,11 +40,9 @@ describe('SplitTestHandler', function () {
}
this.SplitTestCache = {
get: sinon.stub().resolves(null),
}
for (const splitTest of this.splitTests) {
this.SplitTestCache.get.withArgs(splitTest.name).resolves(splitTest)
get: sinon.stub().resolves({}),
}
this.SplitTestCache.get.resolves(this.cachedSplitTests)
this.Settings = {
moduleImportSequence: [],
overleaf: {},
@ -203,22 +205,29 @@ describe('SplitTestHandler', function () {
this.AnalyticsManager.getIdsFromSession.returns({
userId: 'abc123abc123',
})
this.SplitTestCache.get.returns({
name: 'my-test-name',
versions: [
{
versionNumber: 0,
active: true,
variants: [
{
name: '100-percent-variant',
rolloutPercent: 100,
rolloutStripes: [{ start: 0, end: 100 }],
},
],
},
],
})
this.SplitTestCache.get.resolves(
new Map([
[
'my-test-name',
{
name: 'my-test-name',
versions: [
{
versionNumber: 0,
active: true,
variants: [
{
name: '100-percent-variant',
rolloutPercent: 100,
rolloutStripes: [{ start: 0, end: 100 }],
},
],
},
],
},
],
])
)
const assignment = await this.SplitTestHandler.promises.getAssignment(
this.req,