Node.js使用mysql2连接池程序不终止,调用pool.end()报Pool is closed错误
根本原因
mysql2 连接池的query/execute方法在回调触发、Promise resolve之后,内部还有连接回收、资源清理的逻辑会被放到事件循环的后续微任务/队列阶段执行。你在await db.get(data)完成后立刻同步调用db.end()时,mysql2 还没完成活跃连接的回收操作,连接池仍存在未释放的TCP连接句柄,此时调用pool.end()会触发状态冲突,抛出Pool is closed错误。
而你删掉db.end()时,连接池默认会维持空闲连接的TCP句柄,这些活跃句柄会阻止Node.js事件循环清空,导致进程无法自动退出,why-is-node-still-running输出的TCPWRAP就是这些未释放的数据库连接句柄。
为什么延迟调用可以生效
setTimeout、setImmediate、process.nextTick都会把pool.end()的执行时机延迟到当前同步代码、以及mysql2内部的连接回收逻辑执行完成之后,此时连接池处于空闲状态,调用end()可以正常关闭所有连接、释放全部句柄,进程就能正常退出。
规范的解决方案
建议你修改database.js中的end方法,将其包装为Promise,确保关闭操作完成后再结束流程,避免依赖延迟调用的黑盒逻辑:
// database.js 修改end方法 exports.end = () => { return new Promise((resolve, reject) => { pool.end((err) => { if (err) return reject(err); resolve(); }); }); };
主文件中调用时增加await即可:
const db = require("./database"); (async () => { try { const data = { name: "John Doe", email: "johndoe@example.com" }; await db.set(data); const result = await db.get(data); console.log(result); await db.end(); // 等待连接池完全关闭 } catch (err) { console.error(err); process.exit(1); } })();
这种写法既不会触发状态冲突报错,也能保证连接池资源完全释放后进程自动退出,逻辑更可控。
内容的提问来源于stack exchange,提问作者code
相关产品推荐
相关产品推荐

