Merge pull request #5479 from overleaf/bg-refresh-features-on-editor-load

refresh user features on editor load when out of date

GitOrigin-RevId: ef39b5626cfdc6ed611137a6f6eca3417d3ce73f
This commit is contained in:
Brian Gough
2021-10-26 14:31:24 +01:00
committed by Copybot
parent 5862359ff0
commit e681c6322f
7 changed files with 123 additions and 3 deletions
@@ -39,6 +39,7 @@ const AnalyticsManager = require('../Analytics/AnalyticsManager')
const Modules = require('../../infrastructure/Modules')
const SplitTestV2Handler = require('../SplitTests/SplitTestV2Handler')
const { getNewLogsUIVariantForUser } = require('../Helpers/NewLogsUI')
const FeaturesUpdater = require('../Subscription/FeaturesUpdater')
const _ssoAvailable = (affiliation, session, linkedInstitutionIds) => {
if (!affiliation.institution) return false
@@ -661,16 +662,21 @@ const ProjectController = {
} else {
User.findById(
userId,
'email first_name last_name referal_id signUpDate featureSwitches features refProviders alphaProgram betaProgram isAdmin ace',
'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace',
(err, user) => {
// Handle case of deleted user
if (user == null) {
UserController.logout(req, res, next)
return
}
if (err) {
return cb(err)
}
logger.log({ projectId, userId }, 'got user')
cb(err, user)
if (FeaturesUpdater.featuresEpochIsCurrent(user)) {
return cb(null, user)
}
ProjectController._refreshFeatures(req, user, cb)
}
)
}
@@ -893,6 +899,59 @@ const ProjectController = {
)
},
_refreshFeatures(req, user, callback) {
// If the feature refresh has failed in this session, don't retry
// it - require the user to log in again.
if (req.session.feature_refresh_failed) {
metrics.inc('features-refresh', 1, {
path: 'load-editor',
status: 'skipped',
})
return callback(null, user)
}
// If the refresh takes too long then return the current
// features. Note that the user.features property may still be
// updated in the background after the callback is called.
callback = _.once(callback)
const refreshTimeoutHandler = setTimeout(() => {
req.session.feature_refresh_failed = { reason: 'timeout', at: new Date() }
metrics.inc('features-refresh', 1, {
path: 'load-editor',
status: 'timeout',
})
callback(null, user)
}, 5000)
// try to refresh user features now
const timer = new metrics.Timer('features-refresh-on-load-editor')
FeaturesUpdater.refreshFeatures(
user._id,
'load-editor',
(err, features) => {
clearTimeout(refreshTimeoutHandler)
timer.done()
if (err) {
// keep a record to prevent unneceary retries and leave
// the original features unmodified if the refresh failed
req.session.feature_refresh_failed = {
reason: 'error',
at: new Date(),
}
metrics.inc('features-refresh', 1, {
path: 'load-editor',
status: 'error',
})
} else {
user.features = features
metrics.inc('features-refresh', 1, {
path: 'load-editor',
status: 'success',
})
}
return callback(null, user)
}
)
},
_buildProjectList(allProjects, userId) {
let project
const {