refresh_features.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. const { db } = require('../app/src/infrastructure/mongojs')
  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 getMismatchReasons = (currentFeatures, expectedFeatures) => {
  8. if (_.isEqual(currentFeatures, expectedFeatures)) {
  9. return null
  10. }
  11. let mismatchReasons = {}
  12. Object.keys(currentFeatures)
  13. .sort()
  14. .forEach(key => {
  15. if (expectedFeatures[key] !== currentFeatures[key]) {
  16. mismatchReasons[key] = currentFeatures[key]
  17. }
  18. })
  19. return mismatchReasons
  20. }
  21. const normalizeMismatchReasons = mismatchReasons => {
  22. if (mismatchReasons.collaborators > 1 && mismatchReasons.collaborators < 10) {
  23. mismatchReasons.collaborators = 10
  24. }
  25. if (mismatchReasons.collaborators > 10) {
  26. mismatchReasons.collaborators = -1
  27. }
  28. if (mismatchReasons.compileTimeout) {
  29. mismatchReasons.compileTimeout = 240
  30. }
  31. return mismatchReasons
  32. }
  33. const recordMismatch = (user, mismatchReasons) => {
  34. mismatchReasons = normalizeMismatchReasons(mismatchReasons)
  35. const mismatchReasonsString = JSON.stringify(mismatchReasons)
  36. if (allMismatchReasons[mismatchReasonsString]) {
  37. allMismatchReasons[mismatchReasonsString] += 1
  38. } else {
  39. allMismatchReasons[mismatchReasonsString] = 1
  40. }
  41. mismatchUsersCount += 1
  42. if (user.lastLoggedIn) {
  43. let daysSinceLastLoggedIn =
  44. (new Date() - user.lastLoggedIn) / 1000 / 3600 / 24
  45. allDaysSinceLastLoggedIn.push(daysSinceLastLoggedIn)
  46. }
  47. }
  48. const checkAndUpdateUser = (user, callback) =>
  49. FeaturesUpdater._computeFeatures(user._id, (error, freshFeatures) => {
  50. if (error) {
  51. return callback(error)
  52. }
  53. let mismatchReasons = getMismatchReasons(user.features, freshFeatures)
  54. if (!mismatchReasons) {
  55. // features are matching; nothing else to do
  56. return callback()
  57. }
  58. recordMismatch(user, mismatchReasons)
  59. if (!COMMIT) {
  60. // not saving features; nothing else to do
  61. return callback()
  62. }
  63. UserFeaturesUpdater.updateFeatures(user._id, freshFeatures, callback)
  64. })
  65. const updateUsers = (users, callback) =>
  66. async.eachLimit(users, ASYNC_LIMIT, checkAndUpdateUser, error => {
  67. if (error) {
  68. return callback(error)
  69. }
  70. checkedUsersCount += users.length
  71. console.log(
  72. `Users checked: ${checkedUsersCount}. Mismatches: ${mismatchUsersCount}`
  73. )
  74. callback()
  75. })
  76. const loopForUsers = (lastUserId, callback) => {
  77. const query = {}
  78. if (lastUserId) {
  79. query['_id'] = { $gt: lastUserId }
  80. }
  81. db.users
  82. .find(query, { features: 1, lastLoggedIn: 1 })
  83. .limit(FETCH_LIMIT, (error, users) => {
  84. if (error) {
  85. return callback(error)
  86. }
  87. if (users.length === 0) {
  88. console.log('DONE')
  89. return callback()
  90. }
  91. updateUsers(users, error => {
  92. if (error) {
  93. return callback(error)
  94. }
  95. const lastUserId = users[users.length - 1]._id
  96. loopForUsers(lastUserId, callback)
  97. })
  98. })
  99. }
  100. let checkedUsersCount = 0
  101. let mismatchUsersCount = 0
  102. let allDaysSinceLastLoggedIn = []
  103. let allMismatchReasons = {}
  104. const run = () =>
  105. loopForUsers(null, error => {
  106. if (error) {
  107. throw error
  108. }
  109. console.log({ allMismatchReasons })
  110. console.log(
  111. 'Average Last Logged In (Days):',
  112. _.sum(allDaysSinceLastLoggedIn) / allDaysSinceLastLoggedIn.length
  113. )
  114. console.log(
  115. 'Recent Logged In (Last 7 Days):',
  116. _.filter(allDaysSinceLastLoggedIn, a => a < 7).length
  117. )
  118. console.log(
  119. 'Recent Logged In (Last 30 Days):',
  120. _.filter(allDaysSinceLastLoggedIn, a => a < 30).length
  121. )
  122. process.exit()
  123. })
  124. let FETCH_LIMIT, ASYNC_LIMIT, COMMIT
  125. const setup = () => {
  126. const argv = minimist(process.argv.slice(2))
  127. FETCH_LIMIT = argv.fetch ? argv.fetch : 100
  128. ASYNC_LIMIT = argv.async ? argv.async : 10
  129. COMMIT = argv.commit !== undefined
  130. if (!COMMIT) {
  131. console.log('Doing dry run without --commit')
  132. }
  133. }
  134. setup()
  135. run()