NestJS基于ws库的WebSocket服务关闭后进程未退出,端口占用求助
我在WSL2环境下使用NestJS结合ws库搭建WebSocket服务器,遇到以下异常情况:
- 执行
nest start启动HTTP服务器 - 使用Postman连接WebSocket实例
- 在终端按下
Ctrl + C关闭服务进程后,Postman仍显示处于连接状态 - 再次启动服务时出现错误:
Error: listen EADDRINUSE: address already in use :::3000,必须手动杀死占用端口的进程才能重启
若先断开Postman的连接再关闭服务,则能正常重启。之前使用普通Express+ws搭建的服务器不会出现此问题,我原本以为关闭服务器时会自动终止所有客户端连接,但实际并未生效。
补充信息:构建NestJS应用后,在/dist目录执行node main.js运行服务,关闭时能正常断开所有客户端连接,问题似乎与Nest CLI的启动方式有关?
核心原因
Nest CLI的nest start命令默认启用热重载功能(基于ts-node-dev实现),热重载模式下主进程会fork子进程运行应用代码。当按下Ctrl + C时,主进程被终止,但子进程可能未正确捕获终止信号,导致WebSocket服务器的子进程仍持有端口,且未主动关闭客户端连接。
而直接运行node main.js属于单进程模式,收到SIGINT信号后,Nest的生命周期钩子会正常触发,主动关闭所有WebSocket连接并释放端口。
可行解决方案
禁用热重载启动服务
启动时添加--watch false参数关闭热重载,此时服务以单进程模式运行,Ctrl + C会正常触发Nest的 shutdown 流程,主动关闭所有WebSocket连接:nest start --watch false手动监听终止信号(推荐)
在Nest根模块中手动监听进程终止信号,主动关闭WebSocket服务器及所有客户端连接,确保无论启动模式如何都能正常清理:import { Module, OnModuleDestroy } from '@nestjs/common'; import { WebSocketServer } from '@nestjs/websockets'; import { Server } from 'ws'; @Module({}) export class AppModule implements OnModuleDestroy { @WebSocketServer() private wss: Server; async onModuleDestroy() { this.wss.close(() => { console.log('所有WebSocket连接已关闭'); }); } constructor() { // 监听SIGINT(Ctrl+C)和SIGTERM信号 ['SIGINT', 'SIGTERM'].forEach(signal => { process.on(signal, () => { this.wss.close(() => { process.exit(0); }); }); }); } }使用生产模式启动
执行nest start --prod命令,该模式会先构建应用再以单进程方式运行,与直接执行node main.js的行为一致,能正常处理连接关闭:nest start --prod
内容的提问来源于stack exchange,提问作者Brother Bill

