pms-analysis-reports-mcp-server
Version:
PMS analysis reports server handling maintenance reports, equipment analysis, compliance tracking, and performance metrics with ERP access for data extraction
372 lines • 14.3 kB
JavaScript
import { MongoClient } from 'mongodb';
import { config } from './config.js';
import { logger } from './logger.js';
const defaultPoolConfig = {
maxPoolSize: config.mongoMaxPoolSize || 20,
minPoolSize: config.mongoMinPoolSize || 2,
maxIdleTimeMS: 30000, // Close idle connections after 30 seconds
serverSelectionTimeoutMS: config.mongoConnectionTimeout || 10000,
socketTimeoutMS: config.mongoSocketTimeout || 45000,
connectTimeoutMS: config.mongoConnectionTimeout || 10000,
retryWrites: true, // Automatically retry failed writes
retryReads: true // Automatically retry failed reads
};
class MongoConnectionManager {
constructor() {
this.client = null;
this.eltClient = null;
this.engineDataClient = null;
this.isConnecting = false;
this.isEltConnecting = false;
this.isEngineDataConnecting = false;
this.lastHealthCheck = 0;
this.lastEltHealthCheck = 0;
this.lastEngineDataHealthCheck = 0;
this.healthCheckInterval = 30000; // 30 seconds
}
createClientOptions(customConfig) {
const poolConfig = { ...defaultPoolConfig, ...customConfig };
return {
maxPoolSize: poolConfig.maxPoolSize,
minPoolSize: poolConfig.minPoolSize,
maxIdleTimeMS: poolConfig.maxIdleTimeMS,
serverSelectionTimeoutMS: poolConfig.serverSelectionTimeoutMS,
socketTimeoutMS: poolConfig.socketTimeoutMS,
connectTimeoutMS: poolConfig.connectTimeoutMS,
retryWrites: poolConfig.retryWrites,
retryReads: poolConfig.retryReads,
// Additional production-ready options
compressors: ['zlib'], // Enable compression
readPreference: 'primaryPreferred', // Prefer primary but allow secondary reads
w: 'majority', // Wait for majority acknowledgment
journal: true, // Ensure writes are journaled
// Connection pool events for monitoring
monitorCommands: true
};
}
async getMongoClient() {
// Check if we need to perform health check
const now = Date.now();
if (this.client && (now - this.lastHealthCheck) > this.healthCheckInterval) {
await this.performHealthCheck();
}
if (!this.client) {
await this.initializePrimaryConnection();
}
return this.client;
}
async getELTMongoClient() {
// Check if we need to perform health check
const now = Date.now();
if (this.eltClient && (now - this.lastEltHealthCheck) > this.healthCheckInterval) {
await this.performEltHealthCheck();
}
if (!this.eltClient) {
await this.initializeEltConnection();
}
return this.eltClient;
}
async getEngineDataMongoClient() {
// Check if we need to perform health check
const now = Date.now();
if (this.engineDataClient && (now - this.lastEngineDataHealthCheck) > this.healthCheckInterval) {
await this.performEngineDataHealthCheck();
}
if (!this.engineDataClient) {
await this.initializeEngineDataConnection();
}
return this.engineDataClient;
}
async initializePrimaryConnection() {
if (this.isConnecting) {
// Wait for ongoing connection attempt
while (this.isConnecting && !this.client) {
await new Promise(resolve => setTimeout(resolve, 100));
}
return;
}
this.isConnecting = true;
try {
logger.info('Initializing primary MongoDB connection pool');
this.client = new MongoClient(config.mongoUri, this.createClientOptions());
// Set up connection event handlers
this.setupConnectionEventHandlers(this.client, 'primary');
await this.client.connect();
// Verify connection with ping
await this.client.db().admin().ping();
this.lastHealthCheck = Date.now();
logger.info('Primary MongoDB connection pool initialized successfully', {
maxPoolSize: defaultPoolConfig.maxPoolSize,
minPoolSize: defaultPoolConfig.minPoolSize
});
}
catch (error) {
logger.error('Failed to initialize primary MongoDB connection', { error });
this.client = null;
throw error;
}
finally {
this.isConnecting = false;
}
}
async initializeEltConnection() {
if (this.isEltConnecting) {
// Wait for ongoing connection attempt
while (this.isEltConnecting && !this.eltClient) {
await new Promise(resolve => setTimeout(resolve, 100));
}
return;
}
this.isEltConnecting = true;
try {
logger.info('Initializing ELT MongoDB connection pool');
this.eltClient = new MongoClient(config.secondaryDbUri, this.createClientOptions());
// Set up connection event handlers
this.setupConnectionEventHandlers(this.eltClient, 'elt');
await this.eltClient.connect();
// Verify connection with ping
await this.eltClient.db().admin().ping();
this.lastEltHealthCheck = Date.now();
logger.info('ELT MongoDB connection pool initialized successfully', {
maxPoolSize: defaultPoolConfig.maxPoolSize,
minPoolSize: defaultPoolConfig.minPoolSize
});
}
catch (error) {
logger.error('Failed to initialize ELT MongoDB connection', { error });
this.eltClient = null;
throw error;
}
finally {
this.isEltConnecting = false;
}
}
async initializeEngineDataConnection() {
if (this.isEngineDataConnecting) {
// Wait for ongoing connection attempt
while (this.isEngineDataConnecting && !this.engineDataClient) {
await new Promise(resolve => setTimeout(resolve, 100));
}
return;
}
this.isEngineDataConnecting = true;
try {
logger.info('Initializing Engine Data MongoDB connection pool');
this.engineDataClient = new MongoClient(config.thirdDbUri, this.createClientOptions());
// Set up connection event handlers
this.setupConnectionEventHandlers(this.engineDataClient, 'engine-data');
await this.engineDataClient.connect();
// Verify connection with ping
await this.engineDataClient.db().admin().ping();
this.lastEngineDataHealthCheck = Date.now();
logger.info('Engine Data MongoDB connection pool initialized successfully', {
maxPoolSize: defaultPoolConfig.maxPoolSize,
minPoolSize: defaultPoolConfig.minPoolSize
});
}
catch (error) {
logger.error('Failed to initialize Engine Data MongoDB connection', { error });
this.engineDataClient = null;
throw error;
}
finally {
this.isEngineDataConnecting = false;
}
}
setupConnectionEventHandlers(client, connectionType) {
const prefix = connectionType === 'primary' ? 'Primary' :
connectionType === 'elt' ? 'ELT' : 'Engine Data';
client.on('connectionPoolCreated', (event) => {
logger.info(`${prefix} MongoDB connection pool created`, {
address: event.address,
maxPoolSize: event.options?.maxPoolSize
});
});
client.on('connectionPoolClosed', (event) => {
logger.warn(`${prefix} MongoDB connection pool closed`, { address: event.address });
});
client.on('connectionCreated', (event) => {
logger.debug(`${prefix} MongoDB connection created`, {
connectionId: event.connectionId,
address: event.address
});
});
client.on('connectionClosed', (event) => {
logger.debug(`${prefix} MongoDB connection closed`, {
connectionId: event.connectionId,
address: event.address,
reason: event.reason
});
});
client.on('commandStarted', (event) => {
logger.debug(`${prefix} MongoDB command started`, {
commandName: event.commandName,
databaseName: event.databaseName,
requestId: event.requestId
});
});
client.on('commandFailed', (event) => {
logger.error(`${prefix} MongoDB command failed`, {
commandName: event.commandName,
failure: event.failure,
requestId: event.requestId
});
});
}
async performHealthCheck() {
try {
if (this.client) {
await this.client.db().admin().ping();
this.lastHealthCheck = Date.now();
logger.debug('Primary MongoDB health check passed');
}
}
catch (error) {
logger.error('Primary MongoDB health check failed', { error });
// Reset client to force reconnection on next request
await this.closePrimaryConnection();
}
}
async performEltHealthCheck() {
try {
if (this.eltClient) {
await this.eltClient.db().admin().ping();
this.lastEltHealthCheck = Date.now();
logger.debug('ELT MongoDB health check passed');
}
}
catch (error) {
logger.error('ELT MongoDB health check failed', { error });
// Reset client to force reconnection on next request
await this.closeEltConnection();
}
}
async performEngineDataHealthCheck() {
try {
if (this.engineDataClient) {
await this.engineDataClient.db().admin().ping();
this.lastEngineDataHealthCheck = Date.now();
logger.debug('Engine Data MongoDB health check passed');
}
}
catch (error) {
logger.error('Engine Data MongoDB health check failed', { error });
// Reset client to force reconnection on next request
await this.closeEngineDataConnection();
}
}
async closePrimaryConnection() {
if (this.client) {
try {
await this.client.close();
logger.info('Primary MongoDB connection closed');
}
catch (error) {
logger.error('Error closing primary MongoDB connection', { error });
}
finally {
this.client = null;
this.lastHealthCheck = 0;
}
}
}
async closeEltConnection() {
if (this.eltClient) {
try {
await this.eltClient.close();
logger.info('ELT MongoDB connection closed');
}
catch (error) {
logger.error('Error closing ELT MongoDB connection', { error });
}
finally {
this.eltClient = null;
this.lastEltHealthCheck = 0;
}
}
}
async closeEngineDataConnection() {
if (this.engineDataClient) {
try {
await this.engineDataClient.close();
logger.info('Engine Data MongoDB connection closed');
}
catch (error) {
logger.error('Error closing Engine Data MongoDB connection', { error });
}
finally {
this.engineDataClient = null;
this.lastEngineDataHealthCheck = 0;
}
}
}
async closeAllConnections() {
await Promise.all([
this.closePrimaryConnection(),
this.closeEltConnection(),
this.closeEngineDataConnection()
]);
}
getConnectionStats() {
return {
primary: {
connected: !!this.client,
lastHealthCheck: this.lastHealthCheck,
isConnecting: this.isConnecting
},
elt: {
connected: !!this.eltClient,
lastHealthCheck: this.lastEltHealthCheck,
isConnecting: this.isEltConnecting
},
engineData: {
connected: !!this.engineDataClient,
lastHealthCheck: this.lastEngineDataHealthCheck,
isConnecting: this.isEngineDataConnecting
}
};
}
}
// Create singleton instance
const connectionManager = new MongoConnectionManager();
// Export the improved connection functions
export async function getMongoClient() {
return connectionManager.getMongoClient();
}
export async function getELTMongoClient() {
return connectionManager.getELTMongoClient();
}
export async function getEngineDataMongoClient() {
return connectionManager.getEngineDataMongoClient();
}
export async function getDatabase() {
const client = await getMongoClient();
return client.db(config.dbName);
}
export async function getELTDatabase() {
const client = await getELTMongoClient();
return client.db(config.secondaryDbName);
}
export async function getEngineDataDatabase() {
const client = await getEngineDataMongoClient();
return client.db(config.thirdDbName);
}
// Export additional utility functions
export async function closeAllConnections() {
return connectionManager.closeAllConnections();
}
export function getConnectionStats() {
return connectionManager.getConnectionStats();
}
// Handle graceful shutdown
process.on('SIGINT', async () => {
logger.info('Received SIGINT, closing MongoDB connections gracefully');
await closeAllConnections();
process.exit(0);
});
process.on('SIGTERM', async () => {
logger.info('Received SIGTERM, closing MongoDB connections gracefully');
await closeAllConnections();
process.exit(0);
});
//# sourceMappingURL=mongodb.js.map