refresh_features.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. const { db, waitForDb } = require('../app/src/infrastructure/mongodb')
  2. const minimist = require('minimist')
  3. const _ = require('lodash')
  4. const async = require('async')
  5. const FeaturesUpdater = require('../app/src/Features/Subscription/FeaturesUpdater')
  6. const UserFeaturesUpdater = require('../app/src/Features/Subscription/UserFeaturesUpdater')
  7. const ScriptLogger = {
  8. checkedUsersCount: 0,
  9. mismatchUsersCount: 0,
  10. allDaysSinceLastLoggedIn: [],
  11. allMismatchReasons: {},
  12. recordMismatch: (user, mismatchReasons) => {
  13. const mismatchReasonsString = JSON.stringify(mismatchReasons)
  14. if (ScriptLogger.allMismatchReasons[mismatchReasonsString]) {
  15. ScriptLogger.allMismatchReasons[mismatchReasonsString].push(user._id)
  16. } else {
  17. ScriptLogger.allMismatchReasons[mismatchReasonsString] = [user._id]
  18. }
  19. ScriptLogger.mismatchUsersCount += 1
  20. if (user.lastLoggedIn) {
  21. let daysSinceLastLoggedIn =
  22. (new Date() - user.lastLoggedIn) / 1000 / 3600 / 24
  23. ScriptLogger.allDaysSinceLastLoggedIn.push(daysSinceLastLoggedIn)
  24. }
  25. },
  26. printProgress: () => {
  27. console.warn(
  28. `Users checked: ${ScriptLogger.checkedUsersCount}. Mismatches: ${
  29. ScriptLogger.mismatchUsersCount
  30. }`
  31. )
  32. },
  33. printSummary: () => {
  34. console.log('All Mismatch Reasons:', ScriptLogger.allMismatchReasons)
  35. console.log('Mismatch Users Count', ScriptLogger.mismatchUsersCount)
  36. console.log(
  37. 'Average Last Logged In (Days):',
  38. _.sum(ScriptLogger.allDaysSinceLastLoggedIn) /
  39. ScriptLogger.allDaysSinceLastLoggedIn.length
  40. )
  41. console.log(
  42. 'Recent Logged In (Last 7 Days):',
  43. _.filter(ScriptLogger.allDaysSinceLastLoggedIn, a => a < 7).length
  44. )
  45. console.log(
  46. 'Recent Logged In (Last 30 Days):',
  47. _.filter(ScriptLogger.allDaysSinceLastLoggedIn, a => a < 30).length
  48. )
  49. }
  50. }
  51. const checkAndUpdateUser = (user, callback) =>
  52. FeaturesUpdater._computeFeatures(user._id, (error, freshFeatures) => {
  53. if (error) {
  54. return callback(error)
  55. }
  56. let mismatchReasons = FeaturesUpdater.compareFeatures(
  57. user.features,
  58. freshFeatures
  59. )
  60. if (Object.keys(mismatchReasons).length === 0) {
  61. // features are matching; nothing else to do
  62. return callback()
  63. }
  64. ScriptLogger.recordMismatch(user, mismatchReasons)
  65. if (!COMMIT) {
  66. // not saving features; nothing else to do
  67. return callback()
  68. }
  69. UserFeaturesUpdater.overrideFeatures(user._id, freshFeatures, callback)
  70. })
  71. const checkAndUpdateUsers = (users, callback) =>
  72. async.eachLimit(users, ASYNC_LIMIT, checkAndUpdateUser, callback)
  73. const loopForUsers = (skip, callback) => {
  74. db.users
  75. .find({})
  76. .project({ features: 1, lastLoggedIn: 1 })
  77. .sort('_id')
  78. .skip(skip)
  79. .limit(FETCH_LIMIT)
  80. .toArray((error, users) => {
  81. if (error) {
  82. return callback(error)
  83. }
  84. if (users.length === 0) {
  85. console.warn('DONE')
  86. return callback()
  87. }
  88. checkAndUpdateUsers(users, error => {
  89. if (error) {
  90. return callback(error)
  91. }
  92. ScriptLogger.checkedUsersCount += users.length
  93. retryCounter = 0
  94. ScriptLogger.printProgress()
  95. ScriptLogger.printSummary()
  96. loopForUsers(MONGO_SKIP + ScriptLogger.checkedUsersCount, callback)
  97. })
  98. })
  99. }
  100. let retryCounter = 0
  101. const run = () =>
  102. loopForUsers(MONGO_SKIP + ScriptLogger.checkedUsersCount, error => {
  103. if (error) {
  104. if (retryCounter < 3) {
  105. console.error(error)
  106. retryCounter += 1
  107. console.warn(`RETRYING IN 60 SECONDS. (${retryCounter}/3)`)
  108. return setTimeout(run, 6000)
  109. }
  110. throw error
  111. }
  112. process.exit()
  113. })
  114. let FETCH_LIMIT, ASYNC_LIMIT, COMMIT, MONGO_SKIP
  115. const setup = () => {
  116. const argv = minimist(process.argv.slice(2))
  117. FETCH_LIMIT = argv.fetch ? argv.fetch : 100
  118. ASYNC_LIMIT = argv.async ? argv.async : 10
  119. MONGO_SKIP = argv.skip ? argv.skip : 0
  120. COMMIT = argv.commit !== undefined
  121. if (!COMMIT) {
  122. console.warn('Doing dry run without --commit')
  123. }
  124. if (MONGO_SKIP) {
  125. console.warn(`Skipping first ${MONGO_SKIP} records`)
  126. }
  127. }
  128. waitForDb().then(() => {
  129. setup()
  130. run()
  131. })