记录日期:2026-02-05
celoria-api 频繁重启(PM2 显示 30+ 次重启),用户访问时看到 "Network Error" 页面。
PM2 状态显示:
restarts: 34
uptime: 55s (不断重置)
Heap Usage: 92.33%
错误日志中的关键错误:
sorry, too many clients already
severity: 'FATAL'
系统中存在 3 个独立的数据库连接池,各自管理自己的连接:
| 连接池 | 位置 | Max 连接数 |
|---|---|---|
| Pool 1 | server.js:228 直接 new Pool() |
20 |
| Pool 2 | database/pool.js 模块加载时创建 |
20 |
| Pool 3 | database/sync-pool.js |
10 |
| 总计 | 50 |
原来的关闭逻辑:
// server.js - 修改前
process.on('SIGTERM', () => {
console.log('🛑 收到SIGTERM信号,正在关闭服务器...');
process.exit(0); // 直接退出!没有关闭数据库连接!
});
process.exit(0) 退出,完全没有关闭任何数据库连接池!
删除 server.js 中直接创建 pool 的代码,改用 database/pool.js 的统一管理:
// server.js - 修改后
const {
getPool,
gracefulShutdown: gracefulShutdownPool,
reconnectPool,
} = require('./database/pool');
// 使用统一的连接池
let pool = getPool();
// 初始化数据访问层,使用同一个 pool
initializeDataAccess(pool);
// server.js - 修改后
const gracefulShutdown = async (signal) => {
console.log(`🛑 收到${signal}信号,正在优雅关闭服务器...`);
try {
// 1. 停止接受新请求
server.close(() => {
console.log('✅ HTTP 服务器已停止接受新连接');
});
// 2. 关闭主数据库连接池 (database/pool.js)
console.log('🔄 正在关闭主数据库连接池...');
const poolShutdownResult = await gracefulShutdownPool();
console.log(`✅ 主数据库连接池已关闭: ${poolShutdownResult.message}`);
// 3. 关闭同步数据库连接池 (sync-pool.js)
try {
const syncPool = require('./database/sync-pool');
if (syncPool && syncPool.close) {
console.log('🔄 正在关闭同步数据库连接池...');
await syncPool.close();
console.log('✅ 同步数据库连接池已关闭');
}
} catch (syncError) {
console.log('ℹ️ 同步数据库连接池未初始化或已关闭');
}
console.log('✅ 所有资源已释放,服务器正在退出...');
process.exit(0);
} catch (error) {
console.error('❌ 优雅关闭过程中发生错误:', error.message);
process.exit(1);
}
};
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
使用 reconnectPool() 替代直接创建新 Pool:
// 修改前
await pool.end();
pool = new Pool(newPoolConfig);
// 修改后
const reconnectResult = await reconnectPool(newPoolConfig);
pool = getPool();
initializeDataAccess(pool);
🛑 收到SIGINT信号,正在优雅关闭服务器...
🔄 正在关闭主数据库连接池...
✅ 主数据库连接池已关闭: Pool closed successfully
🔄 正在关闭同步数据库连接池...
✅ 同步数据库连接池已关闭
✅ 所有资源已释放,服务器正在退出...
不要在多个地方创建 new Pool()。应该有一个统一的连接池管理模块,所有地方都从这个模块获取连接池实例。
process.exit() 之前必须:
sorry, too many clients already 直接指向了问题:数据库连接数超限。结合服务频繁重启的现象,可以推断出连接泄漏的问题。
| 文件 | 修改内容 |
|---|---|
backend/server.js |
删除直接创建 Pool,使用 getPool(),实现优雅关闭 |
backend/database/pool.js |
提供 getPool(), gracefulShutdown(), reconnectPool() |
backend/database/sync-pool.js |
提供 close() 方法用于优雅关闭 |
new Pool() 出现在非 database/pool.js 的地方