refresh_features.js 4.1 KB

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