Making getAnalyticsIdFromMongoUser private to UserAnalyticsIdCache (#16125)

* Making getAnalyticsIdFromMongoUser private to UserAnalyticsIdCache

* renaming userAnalyticsIdCache to UserAnalyticsIdCache

* deleting function _getAnalyticsIdFromMongoUser

* renaming userAnalyticsIdCache to UserAnalyticsIdCache part 2

* format:fix

* adding upperCamelCase

* capital case first letter

GitOrigin-RevId: 2e9c18c544b8cffb53838aed56e1ef16979606a5
This commit is contained in:
Davinder Singh 2024-01-05 12:27:57 +00:00 committed by Copybot
parent 9804ebe12c
commit 5c5a01777c
7 changed files with 116 additions and 102 deletions

View file

@ -1,8 +0,0 @@
function getAnalyticsIdFromMongoUser(user) {
// ensure `analyticsId` is set to the user's `analyticsId`, and fallback to their `userId` for pre-analyticsId users
return user.analyticsId || user._id
}
module.exports = {
getAnalyticsIdFromMongoUser,
}

View file

@ -7,7 +7,6 @@ const crypto = require('crypto')
const _ = require('lodash') const _ = require('lodash')
const { expressify } = require('@overleaf/promise-utils') const { expressify } = require('@overleaf/promise-utils')
const logger = require('@overleaf/logger') const logger = require('@overleaf/logger')
const { getAnalyticsIdFromMongoUser } = require('./AnalyticsHelper')
const analyticsEventsQueue = Queues.getQueue('analytics-events') const analyticsEventsQueue = Queues.getQueue('analytics-events')
const analyticsEditingSessionsQueue = Queues.getQueue( const analyticsEditingSessionsQueue = Queues.getQueue(
@ -308,12 +307,11 @@ async function analyticsIdMiddleware(req, res, next) {
const sessionUser = SessionManager.getSessionUser(session) const sessionUser = SessionManager.getSessionUser(session)
if (sessionUser) { if (sessionUser) {
session.analyticsId = getAnalyticsIdFromMongoUser(sessionUser) session.analyticsId = await UserAnalyticsIdCache.get(sessionUser._id)
} else if (!session.analyticsId) { } else if (!session.analyticsId) {
// generate an `analyticsId` if needed // generate an `analyticsId` if needed
session.analyticsId = crypto.randomUUID() session.analyticsId = crypto.randomUUID()
} }
next() next()
} }

View file

@ -1,6 +1,6 @@
const UserGetter = require('../User/UserGetter') const UserGetter = require('../User/UserGetter')
const { CacheLoader } = require('cache-flow') const { CacheLoader } = require('cache-flow')
const { getAnalyticsIdFromMongoUser } = require('./AnalyticsHelper') const { callbackify } = require('util')
class UserAnalyticsIdCache extends CacheLoader { class UserAnalyticsIdCache extends CacheLoader {
constructor() { constructor() {
@ -13,7 +13,7 @@ class UserAnalyticsIdCache extends CacheLoader {
async load(userId) { async load(userId) {
const user = await UserGetter.promises.getUser(userId, { analyticsId: 1 }) const user = await UserGetter.promises.getUser(userId, { analyticsId: 1 })
if (user) { if (user) {
return getAnalyticsIdFromMongoUser(user) return user.analyticsId || user._id.toString()
} }
} }
@ -24,4 +24,8 @@ class UserAnalyticsIdCache extends CacheLoader {
} }
} }
module.exports = new UserAnalyticsIdCache() const userAnalyticsIdCache = new UserAnalyticsIdCache()
userAnalyticsIdCache.callbacks = {
get: callbackify(userAnalyticsIdCache.get).bind(userAnalyticsIdCache),
}
module.exports = userAnalyticsIdCache

View file

@ -9,7 +9,7 @@ const ClsiManager = require('./ClsiManager')
const Metrics = require('@overleaf/metrics') const Metrics = require('@overleaf/metrics')
const { RateLimiter } = require('../../infrastructure/RateLimiter') const { RateLimiter } = require('../../infrastructure/RateLimiter')
const SplitTestHandler = require('../SplitTests/SplitTestHandler') const SplitTestHandler = require('../SplitTests/SplitTestHandler')
const { getAnalyticsIdFromMongoUser } = require('../Analytics/AnalyticsHelper') const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache')
const NEW_COMPILE_TIMEOUT_ENFORCED_CUTOFF = new Date('2023-09-18T11:00:00.000Z') const NEW_COMPILE_TIMEOUT_ENFORCED_CUTOFF = new Date('2023-09-18T11:00:00.000Z')
const NEW_COMPILE_TIMEOUT_ENFORCED_CUTOFF_DEFAULT_BASELINE = new Date( const NEW_COMPILE_TIMEOUT_ENFORCED_CUTOFF_DEFAULT_BASELINE = new Date(
@ -178,6 +178,12 @@ module.exports = CompileManager = {
if (owner && owner.alphaProgram) { if (owner && owner.alphaProgram) {
ownerFeatures.compileGroup = 'alpha' ownerFeatures.compileGroup = 'alpha'
} }
UserAnalyticsIdCache.callbacks.get(
owner._id,
function (err, analyticsId) {
if (err) {
return callback(err)
}
const limits = { const limits = {
timeout: timeout:
ownerFeatures.compileTimeout || ownerFeatures.compileTimeout ||
@ -185,12 +191,15 @@ module.exports = CompileManager = {
compileGroup: compileGroup:
ownerFeatures.compileGroup || ownerFeatures.compileGroup ||
Settings.defaultFeatures.compileGroup, Settings.defaultFeatures.compileGroup,
ownerAnalyticsId: getAnalyticsIdFromMongoUser(owner), ownerAnalyticsId: analyticsId,
} }
CompileManager._getCompileBackendClassDetails( CompileManager._getCompileBackendClassDetails(
owner, owner,
limits.compileGroup, limits.compileGroup,
(err, { compileBackendClass, showFasterCompilesFeedbackUI }) => { (
err,
{ compileBackendClass, showFasterCompilesFeedbackUI }
) => {
if (err) return callback(err) if (err) return callback(err)
limits.compileBackendClass = compileBackendClass limits.compileBackendClass = compileBackendClass
limits.showFasterCompilesFeedbackUI = limits.showFasterCompilesFeedbackUI =
@ -208,7 +217,8 @@ module.exports = CompileManager = {
// will have a later cutoff date for the 20s timeout in the next phase // will have a later cutoff date for the 20s timeout in the next phase
// we check the backend class at version 8 (baseline) // we check the backend class at version 8 (baseline)
const backendClassHistory = const backendClassHistory =
owner.splitTests?.['compile-backend-class-n2d'] || [] owner.splitTests?.['compile-backend-class-n2d'] ||
[]
const backendClassBaselineVariant = const backendClassBaselineVariant =
backendClassHistory.find(version => { backendClassHistory.find(version => {
return version.versionNumber === 8 return version.versionNumber === 8
@ -227,7 +237,9 @@ module.exports = CompileManager = {
'compile-timeout-20s-existing-users', 'compile-timeout-20s-existing-users',
(err, assignmentExistingUsers) => { (err, assignmentExistingUsers) => {
if (err) return callback(err) if (err) return callback(err)
if (assignmentExistingUsers?.variant === '20s') { if (
assignmentExistingUsers?.variant === '20s'
) {
limits.timeout = 20 limits.timeout = 20
} }
callback(null, limits) callback(null, limits)
@ -248,6 +260,8 @@ module.exports = CompileManager = {
) )
} }
) )
}
)
}, },
COMPILE_DELAY: 1, // seconds COMPILE_DELAY: 1, // seconds

View file

@ -9,7 +9,6 @@ const { callbackify } = require('util')
const SplitTestCache = require('./SplitTestCache') const SplitTestCache = require('./SplitTestCache')
const { SplitTest } = require('../../models/SplitTest') const { SplitTest } = require('../../models/SplitTest')
const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache') const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache')
const { getAnalyticsIdFromMongoUser } = require('../Analytics/AnalyticsHelper')
const Features = require('../../infrastructure/Features') const Features = require('../../infrastructure/Features')
const SplitTestUtils = require('./SplitTestUtils') const SplitTestUtils = require('./SplitTestUtils')
const Settings = require('@overleaf/settings') const Settings = require('@overleaf/settings')
@ -142,7 +141,7 @@ async function getAssignmentForMongoUser(
} }
return _getAssignment(splitTestName, { return _getAssignment(splitTestName, {
analyticsId: getAnalyticsIdFromMongoUser(user), analyticsId: await UserAnalyticsIdCache.get(user._id),
sync, sync,
user, user,
userId: user._id.toString(), userId: user._id.toString(),

View file

@ -304,7 +304,10 @@ describe('AnalyticsManager', function () {
} }
}, },
}, },
'./UserAnalyticsIdCache': {},
'./UserAnalyticsIdCache': (this.UserAnalyticsIdCache = {
get: sinon.stub().resolves(this.analyticsId),
}),
crypto: { crypto: {
randomUUID: () => this.analyticsId, randomUUID: () => this.analyticsId,
}, },
@ -343,12 +346,14 @@ describe('AnalyticsManager', function () {
await this.AnalyticsManager.analyticsIdMiddleware( await this.AnalyticsManager.analyticsIdMiddleware(
this.req, this.req,
this.res, this.res,
this.next () => {
)
assert.equal(this.analyticsId, this.req.session.analyticsId) assert.equal(this.analyticsId, this.req.session.analyticsId)
}
)
}) })
it('sets session.analyticsId with a legacy user session without an analyticsId', async function () { it('sets session.analyticsId with a legacy user session without an analyticsId', async function () {
this.UserAnalyticsIdCache.get.resolves(this.userId)
this.req.session.user = { this.req.session.user = {
_id: this.userId, _id: this.userId,
analyticsId: undefined, analyticsId: undefined,
@ -356,26 +361,26 @@ describe('AnalyticsManager', function () {
await this.AnalyticsManager.analyticsIdMiddleware( await this.AnalyticsManager.analyticsIdMiddleware(
this.req, this.req,
this.res, this.res,
this.next () => {
)
assert.equal(this.userId, this.req.session.analyticsId) assert.equal(this.userId, this.req.session.analyticsId)
}
)
}) })
it('updates session.analyticsId with a legacy user session without an analyticsId if different', async function () { it('updates session.analyticsId with a legacy user session without an analyticsId if different', async function () {
this.UserAnalyticsIdCache.get.resolves(this.userId)
this.req.session.user = { this.req.session.user = {
_id: this.userId, _id: this.userId,
analyticsId: undefined, analyticsId: undefined,
} }
this.req.analyticsId = 'foo' this.req.analyticsId = 'foo'
await this.AnalyticsManager.analyticsIdMiddleware( this.AnalyticsManager.analyticsIdMiddleware(this.req, this.res, () => {
this.req,
this.res,
this.next
)
assert.equal(this.userId, this.req.session.analyticsId) assert.equal(this.userId, this.req.session.analyticsId)
}) })
})
it('does not update session.analyticsId with a legacy user session without an analyticsId if same', async function () { it('does not update session.analyticsId with a legacy user session without an analyticsId if same', async function () {
this.UserAnalyticsIdCache.get.resolves(this.userId)
this.req.session.user = { this.req.session.user = {
_id: this.userId, _id: this.userId,
analyticsId: undefined, analyticsId: undefined,
@ -384,16 +389,10 @@ describe('AnalyticsManager', function () {
await this.AnalyticsManager.analyticsIdMiddleware( await this.AnalyticsManager.analyticsIdMiddleware(
this.req, this.req,
this.res, this.res,
this.next () => {
)
assert.equal(this.userId, this.req.session.analyticsId) assert.equal(this.userId, this.req.session.analyticsId)
}
await this.AnalyticsManager.analyticsIdMiddleware(
this.req,
this.res,
this.next
) )
assert.equal(this.userId, this.req.session.analyticsId)
}) })
}) })
}) })

View file

@ -37,6 +37,11 @@ describe('CompileManager', function () {
'./ClsiManager': (this.ClsiManager = {}), './ClsiManager': (this.ClsiManager = {}),
'../../infrastructure/RateLimiter': this.RateLimiter, '../../infrastructure/RateLimiter': this.RateLimiter,
'@overleaf/metrics': this.Metrics, '@overleaf/metrics': this.Metrics,
'../Analytics/UserAnalyticsIdCache': (this.UserAnalyticsIdCache = {
callbacks: {
get: sinon.stub().yields(null, 'abc'),
},
}),
'../SplitTests/SplitTestHandler': { '../SplitTests/SplitTestHandler': {
getAssignmentForMongoUser: (this.getAssignmentForMongoUser = sinon getAssignmentForMongoUser: (this.getAssignmentForMongoUser = sinon
.stub() .stub()
@ -177,7 +182,7 @@ describe('CompileManager', function () {
}) })
describe('getProjectCompileLimits', function () { describe('getProjectCompileLimits', function () {
beforeEach(function () { beforeEach(function (done) {
this.features = { this.features = {
compileTimeout: (this.timeout = 42), compileTimeout: (this.timeout = 42),
compileGroup: (this.group = 'priority'), compileGroup: (this.group = 'priority'),
@ -198,7 +203,10 @@ describe('CompileManager', function () {
) )
this.CompileManager.getProjectCompileLimits( this.CompileManager.getProjectCompileLimits(
this.project_id, this.project_id,
this.callback (err, res) => {
this.callback(err, res)
done()
}
) )
}) })