You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExpressJS调用app.listen后Node进程无法正常退出如何解决

问题环境
  • NodeJS v16.15.1
  • Windows 10 操作系统
问题表现
  • 代码中调用Express的app.listen()启动服务后,nodemon、VSCode均无法正常终止对应的Node进程
  • 代码变更触发nodemon自动重启时,控制台仅输出[nodemon] restarting due to changes...后就无后续响应,必须手动打开任务管理器结束对应进程才能继续操作
  • 手动在nodemon控制台输入rs指令触发重启同样卡死无响应,添加nodemon --signal SIGTERM启动参数也无改善,进程始终无法接收SIGTERM信号
  • 移除app.listen()调用后,nodemon和VSCode的进程重启功能完全恢复正常
  • 异常触发时无任何报错信息,进程仅卡住不退出

问题最小复现代码:

'use strict';
const express = require('express');
const app = express();
const PORT = 8040;
// 问题触发代码行
app.listen(PORT, () => {
  console.log(`Started on http://localhost:${PORT} (PID: ${process.pid})`);
});

手动触发重启卡死截图:
输入rs无响应截图

使用why-is-node-running包检测维持进程运行的句柄,结果如下:

There are 5 handle(s) keeping the process running

# TCPSERVERWRAP
C:\services\overview\node_modules\express\lib\application.js:635 - return server.listen.apply(server, arguments);
C:\services\overview\src\tmp2.js:6                               - app.listen(PORT, () => {

# TTYWRAP
C:\services\overview\src\tmp2.js:7 - console.log(`Started on http://localhost:${PORT} (PID: ${process.pid})`);

# HTTPINCOMINGMESSAGE
(unknown stack trace)

# HTTPINCOMINGMESSAGE
(unknown stack trace)

# TickObject
(unknown stack trace)
问题原因

这是Windows平台下NodeJS 16.15.x版本的已知底层bug,和Express框架本身无关:该版本Node在Windows系统上的信号处理逻辑存在缺陷,当存在活跃的TCP Server监听句柄时,进程收到SIGINT、SIGTERM等终止信号后无法正确回收TCP句柄,直接进入卡死状态无法退出。

解决方案

按优先级从高到低选择即可:

  • 升级NodeJS版本
    直接升级到Node 16.16.0及以上的16.x补丁版本,或是升级到18.x、20.x等长期支持版本,该bug已经在后续官方版本中被修复,升级后无需修改业务代码即可解决问题。
  • 代码层兼容(无法升级Node版本时使用)
    显式监听进程终止信号,手动关闭app.listen()返回的服务实例,主动释放TCP句柄,修改后的代码示例:
    'use strict';
    const express = require('express');
    const app = express();
    const PORT = 8040;
    
    const server = app.listen(PORT, () => {
      console.log(`Started on http://localhost:${PORT} (PID: ${process.pid})`);
    });
    
    // 手动处理终止信号,主动释放服务句柄
    const gracefulShutdown = () => {
      server.close(() => {
        process.exit(0);
      });
      // 加1秒超时强制退出,避免意外的句柄泄漏导致卡死
      setTimeout(() => process.exit(1), 1000).unref();
    };
    process.on('SIGTERM', gracefulShutdown);
    process.on('SIGINT', gracefulShutdown);
    
  • nodemon配置兼容
    在nodemon配置文件中开启legacy监听模式,同时指定终止信号为SIGINT,部分场景下也能缓解卡死问题,配置示例:
    // nodemon.json
    {
      "signal": "SIGINT",
      "legacyWatch": true
    }
    

内容的提问来源于stack exchange,提问作者Marc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:09:38