const mongoose = require('mongoose'); require('./models'); // Load all schemas /** * Connect to MongoDB with reconnection logic * @param {string} uri - MongoDB connection URI (from process.env.MONGODB_URI) * @param {object} options - Optional Mongoose connection options * @returns {Promise} */ async function connectMongoDB(uri, options = {}) { if (!uri) { throw new Error('MONGODB_URI is required. Add it to your .env file.'); } const defaultOptions = { serverSelectionTimeoutMS: 5000, socketTimeoutMS: 45000, ...options }; try { await mongoose.connect(uri, defaultOptions); console.log('✓ Connected to MongoDB'); mongoose.connection.on('error', (err) => { console.error('MongoDB connection error:', err); }); mongoose.connection.on('disconnected', () => { console.warn('MongoDB disconnected. Attempting to reconnect...'); }); mongoose.connection.on('reconnected', () => { console.log('✓ MongoDB reconnected'); }); } catch (err) { console.error('Failed to connect to MongoDB:', err.message); console.error('Stack:', err.stack); throw err; } } /** * Gracefully close MongoDB connection * @returns {Promise} */ async function closeMongoDB() { try { await mongoose.connection.close(); console.log('MongoDB connection closed'); } catch (err) { console.error('Error closing MongoDB:', err); } } /** * Retry a function on Mongoose connection errors. * @param {Function} fn - async function to execute * @param {object} options - { retries: 3, delayMs: 500 } * @returns {Promise<*>} */ async function withRetry(fn, options = {}) { const { retries = 3, delayMs = 500 } = options; let lastError; for (let attempt = 0; attempt <= retries; attempt++) { try { return await fn(); } catch (err) { lastError = err; const isConnectionError = err.name === 'MongoNetworkError' || mongoose.connection.readyState !== 1; if (!isConnectionError || attempt >= retries) throw err; await new Promise(r => setTimeout(r, delayMs)); } } throw lastError; } module.exports = { connectMongoDB, closeMongoDB, withRetry, mongoose };