import { env } from "@config/env";
import { getLogger } from "@utils/asyncLocalStorage";
import mongoose from "mongoose";
/**
* MongoDB connection options used for the service-level connection pool.
* @category Database
*/
const mongoOptions = {
// Connection pool settings
maxPoolSize: 10,
minPoolSize: 5,
maxIdleTimeMS: 30000, // Close connections after 30 seconds of inactivity
// Connection timeout settings
serverSelectionTimeoutMS: 5000, // How long to try selecting a server
socketTimeoutMS: 45000, // How long to wait for a response
connectTimeoutMS: 10000, // How long to wait for initial connection
// Retry settings
retryWrites: true,
retryReads: true,
// Buffer settings
bufferCommands: false, // Disable mongoose buffering
};
let isConnected = false;
let connectionAttempts = 0;
const maxConnectionAttempts = 5;
/**
* Connect to MongoDB using the configured connection options.
* @category Database
* @returns {Promise<void>} Resolves when the connection is established.
* @throws {unknown} Propagates connection errors once the retry budget is exhausted.
*/
export async function connectToDatabase() {
const logger = getLogger();
if (isConnected) {
logger.info("Database already connected");
return;
}
try {
logger.info({
uri: env.MONGO_URI.replace(/\/\/.*@/, "//***:***@"), // Hide credentials in logs
options: mongoOptions,
}, "Attempting to connect to MongoDB...");
await mongoose.connect(env.MONGO_URI, mongoOptions);
isConnected = true;
connectionAttempts = 0;
const status = getDatabaseStatus();
logger.info(status, "Successfully connected to MongoDB");
// Set up connection event listeners
setupConnectionEventListeners();
}
catch (error) {
connectionAttempts++;
logger.error({
error: error instanceof Error ? error.message : "Unknown error",
attempt: connectionAttempts,
maxAttempts: maxConnectionAttempts,
}, "Failed to connect to MongoDB");
if (connectionAttempts >= maxConnectionAttempts) {
logger.fatal("Maximum connection attempts reached. Exiting...");
process.exit(1);
}
// Retry connection after delay
const retryDelay = Math.min(1000 * Math.pow(2, connectionAttempts), 30000);
logger.info({ retryDelay }, "Retrying connection...");
setTimeout(() => {
void connectToDatabase();
}, retryDelay);
}
}
/**
* Register listeners for Mongo connection lifecycle events.
* @category Database
*/
function setupConnectionEventListeners() {
const logger = getLogger();
const connection = mongoose.connection;
connection.on("connected", () => {
logger.info("MongoDB connection established");
});
connection.on("error", (error) => {
logger.error({ error: error.message }, "MongoDB connection error");
});
connection.on("disconnected", () => {
isConnected = false;
logger.warn("MongoDB disconnected");
});
connection.on("reconnected", () => {
isConnected = true;
logger.info("MongoDB reconnected");
});
connection.on("close", () => {
isConnected = false;
logger.warn("MongoDB connection closed");
});
}
/**
* Close the active MongoDB connection if one exists.
* @category Database
* @returns {Promise<void>} Resolves after the connection is terminated.
*/
export async function closeDatabaseConnection() {
const logger = getLogger();
if (!isConnected) {
logger.info("Database not connected, skipping close");
return;
}
try {
logger.info("Closing MongoDB connection...");
await mongoose.connection.close();
isConnected = false;
logger.info("MongoDB connection closed successfully");
}
catch (error) {
logger.error({
error: error instanceof Error ? error.message : "Unknown error",
}, "Error closing MongoDB connection");
}
}
/**
* Snapshot of the current MongoDB connection state.
* @category Database
* @returns {object} Connection metadata.
*/
export function getDatabaseStatus() {
const connection = mongoose.connection;
return {
isConnected,
readyState: connection.readyState,
host: connection.host,
port: connection.port,
name: connection.name,
};
}
Source