cubeforall-dbconnection
Version:
A centralized MongoDB connection handler with connection pooling and graceful shutdown support.
161 lines (141 loc) • 4.98 kB
JavaScript
const { MongoClient } = require("mongodb");
const dotenv = require("dotenv");
dotenv.config();
const { ObjectId, GridFSBucket, Timestamp, Binary } = require("mongodb");
const mongoClients = {}; // Store clients dynamically
/**
* Initialize a MongoDB connection dynamically with retry
* @param {string} name - Connection name (e.g., "boxMongo", "platformMongo")
* @param {string} url - MongoDB connection URL
* @param {object} options - Additional connection options (optional)
* @param {number} retryAttempts - Number of retry attempts (default 3)
* @param {number} retryInterval - Interval between retries in ms (default 1000ms)
*/
async function connectMongoDB(name, url, options = {}, retryAttempts = 3, retryInterval = 1000) {
if (!url) throw new Error(`Database URL for ${name} is required.`);
// If connection exists and is active, return it
if (mongoClients[name] && mongoClients[name].topology?.isConnected()) {
return mongoClients[name];
}
let attempt = 0;
let connected = false;
const clientOptions = {
maxPoolSize: 10,
minPoolSize: 5,
maxIdleTimeMS: 30000,
useUnifiedTopology: true,
...options,
};
while (attempt < retryAttempts && !connected) {
try {
console.log(`🔄 Connecting to MongoDB (${name}), Attempt ${attempt + 1}/${retryAttempts}`);
mongoClients[name] = new MongoClient(url, clientOptions);
await mongoClients[name].connect();
connected = true;
console.log(`✅ Connected to MongoDB (${name})`);
return mongoClients[name];
} catch (err) {
console.error(`❌ Failed to connect to MongoDB (${name}) on attempt ${attempt + 1}:`, err.message);
attempt++;
if (attempt < retryAttempts) {
await new Promise((resolve) => setTimeout(resolve, retryInterval));
} else {
throw new Error(`Failed to connect to MongoDB (${name}) after ${retryAttempts} attempts.`);
}
}
}
}
/**
* Get a database instance from the specified connection
* @param {string} name - Connection name
* @param {string} dbName - Database name
*/
async function getDatabase(name, dbName) {
const client = mongoClients[name];
if (!client) throw new Error(`No active connection found for ${name}`);
return client.db(dbName);
}
/**
* Get a collection from a specific database
* @param {string} name - Connection name
* @param {string} dbName - Database name
* @param {string} collectionName - Collection name
*/
async function getCollection(name, dbName, collectionName) {
const client = mongoClients[name];
if (!client || !client.topology?.isConnected()) {
throw new Error(`No active connection found for ${name}. Make sure connectMongoDB() was called.`);
}
const db = await getDatabase(name, dbName);
return db.collection(collectionName);
}
/**
* Get raw MongoClient instance
* @param {string} name - Connection name
*/
function getClient(name) {
return mongoClients[name] || null;
}
/**
* Close all active MongoDB connections
*/
async function closeAllConnections() {
for (const [name, client] of Object.entries(mongoClients)) {
if (client) {
await client.close();
console.log(`🛑 MongoDB connection (${name}) closed.`);
}
}
}
/**
* Get MongoDB server connection statuses
*/
async function getMongoDBStatus() {
const statuses = {};
try {
for (const name of Object.keys(mongoClients)) {
const client = mongoClients[name];
if (client && client.topology?.isConnected()) {
const adminDb = client.db("admin");
const status = await adminDb.command({ serverStatus: 1 });
statuses[name] = status.connections;
} else {
statuses[name] = "Disconnected";
}
}
} catch (error) {
console.error("Error fetching MongoDB status:", error);
return { error: "Failed to fetch MongoDB connection status" };
}
return statuses;
}
// Automatically close all connections on exit
process.on('exit', async () => {
console.log('Process is exiting...');
await closeAllConnections();
});
// Handle uncaught exceptions to ensure connections are closed
process.on('uncaughtException', async (err) => {
console.error('Uncaught exception:', err);
await closeAllConnections();
process.exit(1);
});
// Handle uncaught promise rejections
process.on('unhandledRejection', async (reason) => {
console.error('Unhandled rejection:', reason);
await closeAllConnections();
process.exit(1);
});
module.exports = {
connectMongoDB,
getDatabase,
getCollection,
getClient,
closeAllConnections,
getMongoDBStatus,
// Expose commonly used MongoDB classes
ObjectId,
GridFSBucket,
Timestamp,
Binary,
};