Merge pull request #2480 from overleaf/ta-refresh-features-script-improve

Refresh Features Script Improvements

GitOrigin-RevId: 1cd0fc3b689cf85760d9a22804bf9cab19e22409
This commit is contained in:
Timothée Alby
2020-01-08 04:17:47 +00:00
committed by Copybot
parent 99d0ebe8b1
commit 850d5f957c
4 changed files with 161 additions and 190 deletions
+73 -94
View File
@@ -5,58 +5,53 @@ const async = require('async')
const FeaturesUpdater = require('../app/src/Features/Subscription/FeaturesUpdater')
const UserFeaturesUpdater = require('../app/src/Features/Subscription/UserFeaturesUpdater')
const getMismatchReasons = (currentFeatures, expectedFeatures) => {
currentFeatures = _.clone(currentFeatures)
expectedFeatures = _.clone(expectedFeatures)
if (_.isEqual(currentFeatures, expectedFeatures)) {
return {}
}
const ScriptLogger = {
checkedUsersCount: 0,
mismatchUsersCount: 0,
allDaysSinceLastLoggedIn: [],
allMismatchReasons: {},
let mismatchReasons = {}
Object.keys(currentFeatures)
.sort()
.forEach(key => {
if (expectedFeatures[key] !== currentFeatures[key]) {
mismatchReasons[key] = expectedFeatures[key]
}
})
if (mismatchReasons.compileTimeout) {
// store the compile timeout difference instead of the new compile timeout
mismatchReasons.compileTimeout =
expectedFeatures.compileTimeout - currentFeatures.compileTimeout
}
if (mismatchReasons.collaborators) {
// store the collaborators difference instead of the new number only
// replace -1 by 100 to make it clearer
if (expectedFeatures.collaborators === -1) {
expectedFeatures.collaborators = 100
recordMismatch: (user, mismatchReasons) => {
const mismatchReasonsString = JSON.stringify(mismatchReasons)
if (ScriptLogger.allMismatchReasons[mismatchReasonsString]) {
ScriptLogger.allMismatchReasons[mismatchReasonsString].push(user._id)
} else {
ScriptLogger.allMismatchReasons[mismatchReasonsString] = [user._id]
}
if (currentFeatures.collaborators === -1) {
currentFeatures.collaborators = 100
ScriptLogger.mismatchUsersCount += 1
if (user.lastLoggedIn) {
let daysSinceLastLoggedIn =
(new Date() - user.lastLoggedIn) / 1000 / 3600 / 24
ScriptLogger.allDaysSinceLastLoggedIn.push(daysSinceLastLoggedIn)
}
mismatchReasons.collaborators =
expectedFeatures.collaborators - currentFeatures.collaborators
}
},
return mismatchReasons
}
printProgress: () => {
console.warn(
`Users checked: ${ScriptLogger.checkedUsersCount}. Mismatches: ${
ScriptLogger.mismatchUsersCount
}`
)
},
const recordMismatch = (user, mismatchReasons) => {
const mismatchReasonsString = JSON.stringify(mismatchReasons)
if (allMismatchReasons[mismatchReasonsString]) {
allMismatchReasons[mismatchReasonsString] += 1
} else {
allMismatchReasons[mismatchReasonsString] = 1
}
mismatchUsersCount += 1
if (user.lastLoggedIn) {
let daysSinceLastLoggedIn =
(new Date() - user.lastLoggedIn) / 1000 / 3600 / 24
allDaysSinceLastLoggedIn.push(daysSinceLastLoggedIn)
printSummary: () => {
console.log('All Mismatch Reasons:', ScriptLogger.allMismatchReasons)
console.log('Mismatch Users Count', ScriptLogger.mismatchUsersCount)
console.log(
'Average Last Logged In (Days):',
_.sum(ScriptLogger.allDaysSinceLastLoggedIn) /
ScriptLogger.allDaysSinceLastLoggedIn.length
)
console.log(
'Recent Logged In (Last 7 Days):',
_.filter(ScriptLogger.allDaysSinceLastLoggedIn, a => a < 7).length
)
console.log(
'Recent Logged In (Last 30 Days):',
_.filter(ScriptLogger.allDaysSinceLastLoggedIn, a => a < 30).length
)
}
}
@@ -66,13 +61,16 @@ const checkAndUpdateUser = (user, callback) =>
return callback(error)
}
let mismatchReasons = getMismatchReasons(user.features, freshFeatures)
let mismatchReasons = FeaturesUpdater.compareFeatures(
user.features,
freshFeatures
)
if (Object.keys(mismatchReasons).length === 0) {
// features are matching; nothing else to do
return callback()
}
recordMismatch(user, mismatchReasons)
ScriptLogger.recordMismatch(user, mismatchReasons)
if (!COMMIT) {
// not saving features; nothing else to do
@@ -82,83 +80,64 @@ const checkAndUpdateUser = (user, callback) =>
UserFeaturesUpdater.overrideFeatures(user._id, freshFeatures, callback)
})
const updateUsers = (users, callback) =>
async.eachLimit(users, ASYNC_LIMIT, checkAndUpdateUser, error => {
if (error) {
return callback(error)
}
checkedUsersCount += users.length
console.log(
`Users checked: ${checkedUsersCount}. Mismatches: ${mismatchUsersCount}`
)
callback()
})
const checkAndUpdateUsers = (users, callback) =>
async.eachLimit(users, ASYNC_LIMIT, checkAndUpdateUser, callback)
const loopForUsers = (lastUserId, callback) => {
const query = {}
if (lastUserId) {
query['_id'] = { $gt: lastUserId }
}
const loopForUsers = (skip, callback) => {
db.users
.find(query, { features: 1, lastLoggedIn: 1 })
.find({}, { features: 1, lastLoggedIn: 1 })
.sort('_id')
.skip(skip)
.limit(FETCH_LIMIT, (error, users) => {
if (error) {
return callback(error)
}
if (users.length === 0) {
console.log('DONE')
console.warn('DONE')
return callback()
}
updateUsers(users, error => {
checkAndUpdateUsers(users, error => {
if (error) {
return callback(error)
}
const lastUserId = users[users.length - 1]._id
loopForUsers(lastUserId, callback)
ScriptLogger.checkedUsersCount += users.length
retryCounter = 0
ScriptLogger.printProgress()
ScriptLogger.printSummary()
loopForUsers(MONGO_SKIP + ScriptLogger.checkedUsersCount, callback)
})
})
}
const printSummary = () => {
console.log({ allMismatchReasons })
console.log(
'Average Last Logged In (Days):',
_.sum(allDaysSinceLastLoggedIn) / allDaysSinceLastLoggedIn.length
)
console.log(
'Recent Logged In (Last 7 Days):',
_.filter(allDaysSinceLastLoggedIn, a => a < 7).length
)
console.log(
'Recent Logged In (Last 30 Days):',
_.filter(allDaysSinceLastLoggedIn, a => a < 30).length
)
}
let checkedUsersCount = 0
let mismatchUsersCount = 0
let allDaysSinceLastLoggedIn = []
let allMismatchReasons = {}
let retryCounter = 0
const run = () =>
loopForUsers(null, error => {
loopForUsers(MONGO_SKIP + ScriptLogger.checkedUsersCount, error => {
if (error) {
if (retryCounter < 3) {
console.error(error)
retryCounter += 1
console.warn(`RETRYING IN 60 SECONDS. (${retryCounter}/3)`)
return setTimeout(run, 6000)
}
throw error
}
printSummary()
process.exit()
})
let FETCH_LIMIT, ASYNC_LIMIT, COMMIT
let FETCH_LIMIT, ASYNC_LIMIT, COMMIT, MONGO_SKIP
const setup = () => {
const argv = minimist(process.argv.slice(2))
FETCH_LIMIT = argv.fetch ? argv.fetch : 100
ASYNC_LIMIT = argv.async ? argv.async : 10
MONGO_SKIP = argv.skip ? argv.skip : 0
COMMIT = argv.commit !== undefined
if (!COMMIT) {
console.log('Doing dry run without --commit')
console.warn('Doing dry run without --commit')
}
if (MONGO_SKIP) {
console.warn(`Skipping first ${MONGO_SKIP} records`)
}
}