在生产环境中运行Express应用程序时,我希望在服务器进程终止时(即发送SIGTERMSIGINT)正常关闭服务器.

以下是我的代码的简化版本:

const express = require('express');

const app = express();

app.get('/', (req, res) => res.json({ ping: true }));

const server = app.listen(3000, () => console.log('Running…'));

setInterval(() => server.getConnections(
    (err, connections) => console.log(`${connections} connections currently open`)
), 1000);

process.on('SIGTERM', shutDown);
process.on('SIGINT', shutDown);

function shutDown() {
    console.log('Received kill signal, shutting down gracefully');
    server.close(() => {
        console.log('Closed out remaining connections');
        process.exit(0);
    });

    setTimeout(() => {
        console.error('Could not close connections in time, forcefully shutting down');
        process.exit(1);
    }, 10000);
}

当我运行它并调用URL时http://localhost:3000/在浏览器中,setInterval函数中的log语句将一直打印"1连接当前打开",直到我真正关闭浏览器窗口.很明显,即使关闭标签也会保持连接打开.

因此,当我点击Ctrl+C终止服务器时,它将进入超时状态,并在10秒后打印"无法关闭连接",同时继续打印"1连接打开".

只有在终止进程之前关闭浏览器窗口,我才会收到"关闭剩余连接"消息.

What am I missing here? What is the proper way to shut down an Express server gracefully?

推荐答案

我为服务器上打开的连接添加了一个侦听器,将对这些连接的引用存储在一个数组中.当连接关闭时,它们将从数组中删除.

当服务器被终止时,每个连接都会通过调用其end个方法来关闭.对于某些浏览器(例如Chrome),这是不够的,因此在超时后,我会在每个连接上调用destroy.

const express = require('express');

const app = express();

app.get('/', (req, res) => res.json({ ping: true }));

const server = app.listen(3000, () => console.log('Running…'));

setInterval(() => server.getConnections(
    (err, connections) => console.log(`${connections} connections currently open`)
), 1000);

process.on('SIGTERM', shutDown);
process.on('SIGINT', shutDown);

let connections = [];

server.on('connection', connection => {
    connections.push(connection);
    connection.on('close', () => connections = connections.filter(curr => curr !== connection));
});

function shutDown() {
    console.log('Received kill signal, shutting down gracefully');
    server.close(() => {
        console.log('Closed out remaining connections');
        process.exit(0);
    });

    setTimeout(() => {
        console.error('Could not close connections in time, forcefully shutting down');
        process.exit(1);
    }, 10000);

    connections.forEach(curr => curr.end());
    setTimeout(() => connections.forEach(curr => curr.destroy()), 5000);
}

Node.js相关问答推荐

try 使用Puppeteer抓取Twitter时数组空

如何使用多个OR参数从多个集合聚合

如何在Node.js 中设置图表js的背景色

如何在RavenDB中执行JS索引?

MongoDB-$Lookup未获得适当的结果

如何使用Nextjs路由从下一步/导航在新选项卡中通过";router.ush";打开链接

Sass-TypeError:无法读取未定义的属性(正在读取';indexOf';)

当变量在另一个文件中初始化时,在初始化错误之前无法访问变量

NodeJS:zlib.gzipSync 在不同平台上给出不同的明文输出

使用 fs.createWriteStream 将数据写入 bigquery (node.js) 时出现模式错误

无法关闭 node.js 中的mongoose 连接

'{ id: string; 类型的参数}' 不可分配给FindOneOptions类型的参数

即使部署成功,也不会触发 Firebase 函数来填充 Firestore 集合.为什么?

我可以向NPM添加调试脚本吗?

使用 node.js 执行一个 exe 文件

ISODate 未定义

在 Node.js 中的两个不同进程之间进行通信

如何在不全局安装的情况下在 Node REPL 中要求 node 模块?

使用 Monit 而不是基本的 Upstart 设置有什么好处?

如何断言不为空?