mongodb.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. const Metrics = require('@overleaf/metrics')
  2. const { ObjectId } = require('mongodb')
  3. const OError = require('@overleaf/o-error')
  4. const {
  5. addOptionalCleanupHandlerAfterDrainingConnections,
  6. } = require('./GracefulShutdown')
  7. const { getNativeDb } = require('./Mongoose')
  8. if (
  9. typeof global.beforeEach === 'function' &&
  10. process.argv.join(' ').match(/unit/)
  11. ) {
  12. throw new Error(
  13. 'It looks like unit tests are running, but you are connecting to Mongo. Missing a stub?'
  14. )
  15. }
  16. let setupDbPromise
  17. async function waitForDb() {
  18. if (!setupDbPromise) {
  19. setupDbPromise = setupDb()
  20. }
  21. await setupDbPromise
  22. }
  23. const db = {}
  24. async function setupDb() {
  25. const internalDb = await getNativeDb()
  26. collectStatsForDb(internalDb, 'shared')
  27. db.contacts = internalDb.collection('contacts')
  28. db.deletedFiles = internalDb.collection('deletedFiles')
  29. db.deletedProjects = internalDb.collection('deletedProjects')
  30. db.deletedSubscriptions = internalDb.collection('deletedSubscriptions')
  31. db.deletedUsers = internalDb.collection('deletedUsers')
  32. db.dropboxEntities = internalDb.collection('dropboxEntities')
  33. db.dropboxProjects = internalDb.collection('dropboxProjects')
  34. db.docHistory = internalDb.collection('docHistory')
  35. db.docHistoryIndex = internalDb.collection('docHistoryIndex')
  36. db.docOps = internalDb.collection('docOps')
  37. db.docSnapshots = internalDb.collection('docSnapshots')
  38. db.docs = internalDb.collection('docs')
  39. db.feedbacks = internalDb.collection('feedbacks')
  40. db.githubSyncEntityVersions = internalDb.collection(
  41. 'githubSyncEntityVersions'
  42. )
  43. db.githubSyncProjectStates = internalDb.collection('githubSyncProjectStates')
  44. db.githubSyncUserCredentials = internalDb.collection(
  45. 'githubSyncUserCredentials'
  46. )
  47. db.institutions = internalDb.collection('institutions')
  48. db.messages = internalDb.collection('messages')
  49. db.migrations = internalDb.collection('migrations')
  50. db.notifications = internalDb.collection('notifications')
  51. db.oauthAccessTokens = internalDb.collection('oauthAccessTokens')
  52. db.oauthApplications = internalDb.collection('oauthApplications')
  53. db.oauthAuthorizationCodes = internalDb.collection('oauthAuthorizationCodes')
  54. db.projectAuditLogEntries = internalDb.collection('projectAuditLogEntries')
  55. db.projectHistoryChunks = internalDb.collection('projectHistoryChunks')
  56. db.projectHistoryFailures = internalDb.collection('projectHistoryFailures')
  57. db.projectHistoryLabels = internalDb.collection('projectHistoryLabels')
  58. db.projectHistoryMetaData = internalDb.collection('projectHistoryMetaData')
  59. db.projectHistorySyncState = internalDb.collection('projectHistorySyncState')
  60. db.projectInvites = internalDb.collection('projectInvites')
  61. db.projects = internalDb.collection('projects')
  62. db.publishers = internalDb.collection('publishers')
  63. db.rooms = internalDb.collection('rooms')
  64. db.samlCache = internalDb.collection('samlCache')
  65. db.samlLogs = internalDb.collection('samlLogs')
  66. db.spellingPreferences = internalDb.collection('spellingPreferences')
  67. db.splittests = internalDb.collection('splittests')
  68. db.subscriptions = internalDb.collection('subscriptions')
  69. db.surveys = internalDb.collection('surveys')
  70. db.systemmessages = internalDb.collection('systemmessages')
  71. db.tags = internalDb.collection('tags')
  72. db.teamInvites = internalDb.collection('teamInvites')
  73. db.templates = internalDb.collection('templates')
  74. db.tokens = internalDb.collection('tokens')
  75. db.userAuditLogEntries = internalDb.collection('userAuditLogEntries')
  76. db.users = internalDb.collection('users')
  77. db.userstubs = internalDb.collection('userstubs')
  78. }
  79. async function getCollectionNames() {
  80. const internalDb = await getNativeDb()
  81. const collections = await internalDb.collections()
  82. return collections.map(collection => collection.collectionName)
  83. }
  84. async function dropTestDatabase() {
  85. const internalDb = await getNativeDb()
  86. const dbName = internalDb.databaseName
  87. const env = process.env.NODE_ENV
  88. if (dbName !== 'test-sharelatex' || env !== 'test') {
  89. throw new OError(
  90. `Refusing to clear database '${dbName}' in environment '${env}'`
  91. )
  92. }
  93. await internalDb.dropDatabase()
  94. }
  95. /**
  96. * WARNING: Consider using a pre-populated collection from `db` to avoid typos!
  97. */
  98. async function getCollectionInternal(name) {
  99. const internalDb = await getNativeDb()
  100. return internalDb.collection(name)
  101. }
  102. function collectStatsForDb(internalDb, label) {
  103. const collectOnce = () => {
  104. for (const [name, server] of internalDb.s.topology.s.servers.entries()) {
  105. const { availableConnectionCount, waitQueueSize } = server.s.pool
  106. const { maxPoolSize } = server.s.pool.options
  107. const opts = { status: `${label}:${name}` }
  108. Metrics.gauge('mongo_connection_pool_max', maxPoolSize, 1, opts)
  109. Metrics.gauge(
  110. 'mongo_connection_pool_available',
  111. availableConnectionCount,
  112. 1,
  113. opts
  114. )
  115. Metrics.gauge('mongo_connection_pool_waiting', waitQueueSize, 1, opts)
  116. }
  117. }
  118. collectOnce() // init metrics
  119. const intervalHandle = setInterval(collectOnce, 60_000)
  120. addOptionalCleanupHandlerAfterDrainingConnections(
  121. `collect mongo connection pool metrics (${label})`,
  122. () => {
  123. clearInterval(intervalHandle)
  124. // collect one more time.
  125. collectOnce()
  126. }
  127. )
  128. }
  129. module.exports = {
  130. db,
  131. ObjectId,
  132. getCollectionNames,
  133. getCollectionInternal,
  134. dropTestDatabase,
  135. waitForDb,
  136. collectStatsForDb,
  137. }