Просмотр исходного кода

Merge pull request #10735 from overleaf/jpa-mongo-connection-pool-stats

[web] collect metrics for mongo connection pool

GitOrigin-RevId: 71ca95af4e04f124f5ae12c8967ce85d4d9d0428
Jakob Ackermann 3 лет назад
Родитель
Сommit
7fcdd69cee

+ 3 - 0
services/web/app/src/infrastructure/Mongoose.js

@@ -2,6 +2,7 @@ const mongoose = require('mongoose')
 const Settings = require('@overleaf/settings')
 const logger = require('@overleaf/logger')
 const { addConnectionDrainer } = require('./GracefulShutdown')
+const { collectStatsForDb } = require('./mongodb')
 
 if (
   typeof global.beforeEach === 'function' &&
@@ -60,6 +61,8 @@ async function getNativeDb() {
   return mongooseInstance.connection.db
 }
 
+getNativeDb().then(db => collectStatsForDb(db, 'mongoose'))
+
 mongoose.getNativeDb = getNativeDb
 mongoose.connectionPromise = connectionPromise
 

+ 35 - 1
services/web/app/src/infrastructure/mongodb.js

@@ -1,7 +1,11 @@
+const Metrics = require('@overleaf/metrics')
 const Settings = require('@overleaf/settings')
 const { MongoClient, ObjectId } = require('mongodb')
 const OError = require('@overleaf/o-error')
-const { addConnectionDrainer } = require('./GracefulShutdown')
+const {
+  addConnectionDrainer,
+  addOptionalCleanupHandlerAfterDrainingConnections,
+} = require('./GracefulShutdown')
 
 if (
   typeof global.beforeEach === 'function' &&
@@ -32,6 +36,7 @@ async function waitForDb() {
 const db = {}
 async function setupDb() {
   const internalDb = (await clientPromise).db()
+  collectStatsForDb(internalDb, 'native')
 
   db.contacts = internalDb.collection('contacts')
   db.deletedFiles = internalDb.collection('deletedFiles')
@@ -115,6 +120,34 @@ async function getCollectionInternal(name) {
   return internalDb.collection(name)
 }
 
+function collectStatsForDb(internalDb, label) {
+  const collectOnce = () => {
+    for (const [name, server] of internalDb.s.topology.s.servers.entries()) {
+      const { availableConnectionCount, waitQueueSize } = server.s.pool
+      const { maxPoolSize } = server.s.pool.options
+      const opts = { status: `${label}:${name}` }
+      Metrics.gauge('mongo_connection_pool_max', maxPoolSize, 1, opts)
+      Metrics.gauge(
+        'mongo_connection_pool_available',
+        availableConnectionCount,
+        1,
+        opts
+      )
+      Metrics.gauge('mongo_connection_pool_waiting', waitQueueSize, 1, opts)
+    }
+  }
+  collectOnce() // init metrics
+  const intervalHandle = setInterval(collectOnce, 60_000)
+  addOptionalCleanupHandlerAfterDrainingConnections(
+    `collect mongo connection pool metrics (${label})`,
+    () => {
+      clearInterval(intervalHandle)
+      // collect one more time.
+      collectOnce()
+    }
+  )
+}
+
 module.exports = {
   db,
   ObjectId,
@@ -122,4 +155,5 @@ module.exports = {
   getCollectionInternal,
   dropTestDatabase,
   waitForDb,
+  collectStatsForDb,
 }