improve db code

This commit is contained in:
2025-07-10 22:22:57 +03:00
parent 3e4e4bbd77
commit eed8b2dfd2

108
src/db.js
View File

@@ -12,12 +12,18 @@ let clientPromise;
const clientOptions = { const clientOptions = {
maxPoolSize: 10, maxPoolSize: 10,
minPoolSize: 0, minPoolSize: 0,
serverSelectionTimeoutMS: 30000, // Увеличиваем таймауты для медленных соединений
socketTimeoutMS: 45000, serverSelectionTimeoutMS: 60000, // 60 секунд
connectTimeoutMS: 30000, socketTimeoutMS: 0, // Убираем таймаут сокета
connectTimeoutMS: 60000, // 60 секунд
retryWrites: true, retryWrites: true,
w: 'majority', w: 'majority',
// Добавляем настройки для лучшей стабильности
maxIdleTimeMS: 30000,
waitQueueTimeoutMS: 5000,
heartbeatFrequencyMS: 10000,
serverApi: { serverApi: {
version: '1', version: '1',
strict: true, strict: true,
@@ -25,50 +31,110 @@ const clientOptions = {
} }
}; };
// Функция для создания подключения с retry логикой
async function createConnection() {
let attempts = 0;
const maxAttempts = 3;
while (attempts < maxAttempts) {
try {
console.log(`Attempting to connect to MongoDB (attempt ${attempts + 1}/${maxAttempts})...`);
const client = new MongoClient(uri, clientOptions);
await client.connect();
// Проверяем подключение
await client.db().admin().ping();
console.log('MongoDB connection successful');
return client;
} catch (error) {
attempts++;
console.error(`Connection attempt ${attempts} failed:`, error.message);
if (attempts >= maxAttempts) {
throw new Error(`Failed to connect to MongoDB after ${maxAttempts} attempts: ${error.message}`);
}
// Ждем перед следующей попыткой
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
}
// Connection management // Connection management
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value // В режиме разработки используем глобальную переменную
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) { if (!global._mongoClientPromise) {
client = new MongoClient(uri, clientOptions); global._mongoClientPromise = createConnection();
global._mongoClientPromise = client.connect();
console.log('MongoDB connection initialized in development'); console.log('MongoDB connection initialized in development');
} }
clientPromise = global._mongoClientPromise; clientPromise = global._mongoClientPromise;
} else { } else {
// In production mode, it's best to not use a global variable. // В продакшене создаем новое подключение
client = new MongoClient(uri, clientOptions); clientPromise = createConnection();
clientPromise = client.connect();
console.log('MongoDB connection initialized in production'); console.log('MongoDB connection initialized in production');
} }
async function getDb() { async function getDb() {
try { try {
const mongoClient = await clientPromise; const mongoClient = await clientPromise;
// Проверяем, что подключение все еще активно
if (!mongoClient || mongoClient.topology.isDestroyed()) {
throw new Error('MongoDB connection is not available');
}
return mongoClient.db(); return mongoClient.db();
} catch (error) { } catch (error) {
console.error('Error getting MongoDB database:', error); console.error('Error getting MongoDB database:', error);
throw error;
// Пытаемся переподключиться
console.log('Attempting to reconnect...');
if (process.env.NODE_ENV === 'development') {
global._mongoClientPromise = createConnection();
clientPromise = global._mongoClientPromise;
} else {
clientPromise = createConnection();
}
const mongoClient = await clientPromise;
return mongoClient.db();
} }
} }
async function closeConnection() { async function closeConnection() {
if (client) { try {
try { const mongoClient = await clientPromise;
await client.close(true); if (mongoClient) {
client = null; await mongoClient.close(true);
global._mongoClientPromise = null;
console.log('MongoDB connection closed'); console.log('MongoDB connection closed');
} catch (error) {
console.error('Error closing MongoDB connection:', error);
} }
} catch (error) {
console.error('Error closing MongoDB connection:', error);
} finally {
client = null;
if (process.env.NODE_ENV === 'development') {
global._mongoClientPromise = null;
}
}
}
// Функция для проверки подключения
async function checkConnection() {
try {
const db = await getDb();
await db.admin().ping();
console.log('MongoDB connection is healthy');
return true;
} catch (error) {
console.error('MongoDB connection check failed:', error.message);
return false;
} }
} }
// Clean up handlers // Clean up handlers
const cleanup = async () => { const cleanup = async () => {
console.log('Cleaning up MongoDB connection...');
await closeConnection(); await closeConnection();
process.exit(0); process.exit(0);
}; };
@@ -88,4 +154,4 @@ process.on('unhandledRejection', async (reason) => {
process.exit(1); process.exit(1);
}); });
module.exports = { getDb, closeConnection }; module.exports = { getDb, closeConnection, checkConnection };