diff --git a/services/web/app/src/Features/SplitTests/SplitTestCache.js b/services/web/app/src/Features/SplitTests/SplitTestCache.js index 5b61783051..557306d70b 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestCache.js +++ b/services/web/app/src/Features/SplitTests/SplitTestCache.js @@ -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) { diff --git a/services/web/app/src/Features/SplitTests/SplitTestHandler.js b/services/web/app/src/Features/SplitTests/SplitTestHandler.js index fabce8b25b..d450e72f08 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestHandler.js +++ b/services/web/app/src/Features/SplitTests/SplitTestHandler.js @@ -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), diff --git a/services/web/app/src/Features/SplitTests/SplitTestManager.js b/services/web/app/src/Features/SplitTests/SplitTestManager.js index 545c5e062f..b1818d3025 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestManager.js +++ b/services/web/app/src/Features/SplitTests/SplitTestManager.js @@ -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, diff --git a/services/web/test/unit/src/SplitTests/SplitTestHandlerTests.js b/services/web/test/unit/src/SplitTests/SplitTestHandlerTests.js index 308e7098ac..faa3de36d7 100644 --- a/services/web/test/unit/src/SplitTests/SplitTestHandlerTests.js +++ b/services/web/test/unit/src/SplitTests/SplitTestHandlerTests.js @@ -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,