Node.js搭配Postgres使用pool.connect运行一段时间后无响应问题求解
问题根因
你遇到的是数据库连接泄漏问题:node-postgres 默认连接池的最大连接数为 10(部分旧版本默认为 4),你的代码在多个场景下没有正确释放连接,运行几次后连接池被占满,后续 pool.connect() 无法获取到空闲连接,回调函数永远不会执行,所以只会打印 presync 不会打印 connected。
现有代码的连接释放逻辑问题
你当前的释放时机完全不正确,存在多处泄漏点:
- 连接获取报错时,仅打印错误未做拦截,后续代码仍会执行,且无释放逻辑
getStored、fetchLatest两个异步操作如果抛出异常,代码会直接跳出,永远走不到try块内的connection.release()catch块中仅做了重试逻辑,完全没有释放当前已经获取到的连接- 固定间隔的 cron 调度不判断上一次任务是否执行完成,一旦同步逻辑耗时超过10秒就会并发执行,加速连接耗尽
修复方案
1. 重构 doSync 保证所有场景下连接都被释放
改用 async/await 写法替代回调,通过 finally 块强制释放连接:
async function doSync() { console.log("presync"); let connection = null; try { // 用 Promise 方式获取连接,避免回调逻辑遗漏 connection = await db.pool.connect(); console.log("connected"); const stored = parseInt(await getStored("mystorage.txt")); const fetched = parseInt(await fetchLatest(connection)); const query = getQuery(fetched); const cursor = await connection.query(new Cursor(query)); await processResult(cursor, fetched); } catch (err) { console.error("同步任务出错:", err); // 按需添加重试逻辑,不要无限制嵌套重试 } finally { // 核心逻辑:无论执行成功还是失败,只要拿到了连接就必须释放 if (connection) { connection.release(); } } }
2. 调整调度逻辑避免并发
不要用固定间隔的 node-cron 调度,改为「上一次任务执行完成后再间隔10秒发起下一次」,彻底避免并发:
// 启动首次同步,后续任务自行调度 async function startSync() { await doSync(); // 执行完成后等待10秒再执行下一次 setTimeout(startSync, 10000); } startSync();
如果必须保留 node-cron 调度,需要加执行状态锁,避免并发调用:
let isSyncRunning = false; cron.schedule('*/10 * * * * *', async () =>{ // 上一次任务还在执行,直接跳过本次 if (isSyncRunning) return; isSyncRunning = true; try { await doSync(); } finally { isSyncRunning = false; } },{scheduled: true})
这类定时同步场景的最佳实践
- 所有数据库连接必须保证「获取后无论成功失败都要释放」,优先用
try/finally结构保证释放逻辑一定会执行 - 耗时不确定的定时任务不要用固定间隔调度,优先用「执行完成后延迟调度下一次」的模式
- 可以按需调整连接池的最大连接数配置,比如
new Pool({...config.postgres, max: 20}),但前提是必须正确释放连接,否则多大的连接池都会被耗尽 - 生产环境建议添加连接池监控,定期打印当前空闲连接数、占用连接数,方便快速定位泄漏问题
内容的提问来源于stack exchange,提问作者Nothing
相关产品推荐
相关产品推荐

