feat: Initial commit of PDF Tools project
This commit is contained in:
203
server/config/database.js
Normal file
203
server/config/database.js
Normal file
@@ -0,0 +1,203 @@
|
||||
const mongoose = require('mongoose');
|
||||
const redis = require('redis');
|
||||
|
||||
class DatabaseConnection {
|
||||
constructor() {
|
||||
this.mongooseConnection = null;
|
||||
this.redisClient = null;
|
||||
}
|
||||
|
||||
// 连接MongoDB
|
||||
async connectMongoDB() {
|
||||
try {
|
||||
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/pdf-tools';
|
||||
|
||||
this.mongooseConnection = await mongoose.connect(mongoUri, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
serverSelectionTimeoutMS: 5000,
|
||||
maxPoolSize: 10,
|
||||
socketTimeoutMS: 45000,
|
||||
});
|
||||
|
||||
console.log('✅ MongoDB连接成功');
|
||||
|
||||
// 监听连接事件
|
||||
mongoose.connection.on('error', (err) => {
|
||||
console.error('❌ MongoDB连接错误:', err);
|
||||
});
|
||||
|
||||
mongoose.connection.on('disconnected', () => {
|
||||
console.log('⚠️ MongoDB连接断开');
|
||||
});
|
||||
|
||||
mongoose.connection.on('reconnected', () => {
|
||||
console.log('✅ MongoDB重新连接成功');
|
||||
});
|
||||
|
||||
return this.mongooseConnection;
|
||||
} catch (error) {
|
||||
console.error('❌ MongoDB连接失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 连接Redis
|
||||
async connectRedis() {
|
||||
try {
|
||||
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
|
||||
|
||||
this.redisClient = redis.createClient({
|
||||
url: redisUrl,
|
||||
retry_strategy: (options) => {
|
||||
if (options.error && options.error.code === 'ECONNREFUSED') {
|
||||
console.error('❌ Redis服务器拒绝连接');
|
||||
return new Error('Redis服务器拒绝连接');
|
||||
}
|
||||
if (options.total_retry_time > 1000 * 60 * 60) {
|
||||
console.error('❌ Redis重连超时');
|
||||
return new Error('Redis重连超时');
|
||||
}
|
||||
if (options.attempt > 10) {
|
||||
console.error('❌ Redis重连次数超限');
|
||||
return undefined;
|
||||
}
|
||||
// 重连间隔递增
|
||||
return Math.min(options.attempt * 100, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
this.redisClient.on('error', (err) => {
|
||||
console.error('❌ Redis连接错误:', err);
|
||||
});
|
||||
|
||||
this.redisClient.on('connect', () => {
|
||||
console.log('✅ Redis连接成功');
|
||||
});
|
||||
|
||||
this.redisClient.on('reconnecting', () => {
|
||||
console.log('🔄 Redis重新连接中...');
|
||||
});
|
||||
|
||||
this.redisClient.on('ready', () => {
|
||||
console.log('✅ Redis准备就绪');
|
||||
});
|
||||
|
||||
await this.redisClient.connect();
|
||||
return this.redisClient;
|
||||
} catch (error) {
|
||||
console.error('❌ Redis连接失败:', error);
|
||||
// Redis连接失败不应该阻止应用启动
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化所有数据库连接
|
||||
async initialize() {
|
||||
try {
|
||||
// 并行连接数据库
|
||||
const [mongoConnection, redisConnection] = await Promise.allSettled([
|
||||
this.connectMongoDB(),
|
||||
this.connectRedis()
|
||||
]);
|
||||
|
||||
if (mongoConnection.status === 'rejected') {
|
||||
throw new Error(`MongoDB连接失败: ${mongoConnection.reason.message}`);
|
||||
}
|
||||
|
||||
if (redisConnection.status === 'rejected') {
|
||||
console.warn('⚠️ Redis连接失败,将使用内存缓存');
|
||||
}
|
||||
|
||||
console.log('🎉 数据库初始化完成');
|
||||
return {
|
||||
mongodb: mongoConnection.value,
|
||||
redis: redisConnection.status === 'fulfilled' ? redisConnection.value : null
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('❌ 数据库初始化失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭所有连接
|
||||
async close() {
|
||||
try {
|
||||
const promises = [];
|
||||
|
||||
if (this.mongooseConnection) {
|
||||
promises.push(mongoose.connection.close());
|
||||
}
|
||||
|
||||
if (this.redisClient) {
|
||||
promises.push(this.redisClient.quit());
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
console.log('✅ 数据库连接已关闭');
|
||||
} catch (error) {
|
||||
console.error('❌ 关闭数据库连接失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取MongoDB连接状态
|
||||
getMongoStatus() {
|
||||
return {
|
||||
status: mongoose.connection.readyState,
|
||||
host: mongoose.connection.host,
|
||||
port: mongoose.connection.port,
|
||||
name: mongoose.connection.name
|
||||
};
|
||||
}
|
||||
|
||||
// 获取Redis连接状态
|
||||
getRedisStatus() {
|
||||
if (!this.redisClient) {
|
||||
return { status: 'disconnected', message: '未连接' };
|
||||
}
|
||||
|
||||
return {
|
||||
status: this.redisClient.isReady ? 'connected' : 'disconnected',
|
||||
message: this.redisClient.isReady ? '已连接' : '未连接'
|
||||
};
|
||||
}
|
||||
|
||||
// 健康检查
|
||||
async healthCheck() {
|
||||
const health = {
|
||||
mongodb: { status: 'unknown', message: '' },
|
||||
redis: { status: 'unknown', message: '' }
|
||||
};
|
||||
|
||||
try {
|
||||
// MongoDB健康检查
|
||||
if (mongoose.connection.readyState === 1) {
|
||||
await mongoose.connection.db.admin().ping();
|
||||
health.mongodb = { status: 'healthy', message: '连接正常' };
|
||||
} else {
|
||||
health.mongodb = { status: 'unhealthy', message: '连接异常' };
|
||||
}
|
||||
} catch (error) {
|
||||
health.mongodb = { status: 'unhealthy', message: error.message };
|
||||
}
|
||||
|
||||
try {
|
||||
// Redis健康检查
|
||||
if (this.redisClient && this.redisClient.isReady) {
|
||||
await this.redisClient.ping();
|
||||
health.redis = { status: 'healthy', message: '连接正常' };
|
||||
} else {
|
||||
health.redis = { status: 'unhealthy', message: '连接异常' };
|
||||
}
|
||||
} catch (error) {
|
||||
health.redis = { status: 'unhealthy', message: error.message };
|
||||
}
|
||||
|
||||
return health;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const databaseConnection = new DatabaseConnection();
|
||||
|
||||
module.exports = databaseConnection;
|
||||
Reference in New Issue
Block a user