如何在生产模式下优雅地停止一个 Express.js 应用程序
当在生产环境中运行一个Express.js应用时,优雅地处理关闭过程至关重要,以确保用户无缝的体验,避免数据丢失,并保持系统的完整。无论是部署、扩容还是意外的服务器问题,突然关机都可能导致请求未完成、数据损坏或连接中断。
瑞典为什么优雅关机很重要? 为什么优雅地关闭很重要?- 防止数据丢失:确保所有正在进行的请求在关闭连接前完成。
- 释放资源:正确地关闭数据库连接、文件句柄等其他资源。
- 提升用户体验:避免对正在使用系统的用户突然中断。
- 确保干净恢复:确保日志、缓存及其他进程安全刷新并保存到磁盘。
在实际生产中,您的应用程序可能会由像 PM2、Docker 或 Kubernetes 这样的工具管理。这些工具在关闭应用时会发送诸如 SIGINT
(中断信号)或 SIGTERM
(终止信号)之类的信号。在代码中设置侦听器来捕获这些信号。
process.on('SIGTERM', () => {
console.log('接收到 SIGTERM 信号:正在关闭中 HTTP 服务器...');
});
process.on('SIGINT', () => {
console.log('接收到 SIGINT 信号:正在关闭中 HTTP 服务器...');
});
2. 别再接受新的请求了
在你的服务器实例上使用close()
方法,来停止接受新的连接请求。这可以防止应用程序在关闭过程中继续处理新的请求。
const server = app.listen(3000, () => {
console.log('服务器正在端口3000上运行');
});
process.on('SIGTERM', () => {
server.close(() => {
console.log('HTTP服务器已经关闭了。');
});
});
重点:这一点需要注意,close()
方法只会阻止新连接,但允许已有的连接继续完成。
确保所有飞行中的请求得到妥善处理。中间件可以帮助你监控或记录关机过程中正在进行的请求。
app.use((req, res, next) => {
if (process.env['SHUTTING_DOWN']) {
res.setHeader('Connection', 'close');
}
next();
});
process.on('SIGTERM', () => { // 当接收到 SIGTERM 信号时
process.env['SHUTTING_DOWN'] = true;
server.close(() => {
console.log('HTTP服务器已成功关闭。');
});
});
4. 搞定数据库连接及其他资源
你的应用程序可能依赖于数据库、缓存或消息队列等资源。确保在关闭时正确关闭这些资源。
例如,可以这样关闭一个 MongoDB 连接:
const mongoose = require('mongoose');
process.on('SIGTERM', async () => {
try {
await mongoose.connection.close();
console.log('MongoDB 连接已断开。');
process.exit(0);
} catch (err) {
console.error('关闭 MongoDB 连接失败: ' + err);
process.exit(1);
}
});
5. 清空日志并清理
在使用日志工具或缓存的情况下,确保在退出前清空并清理干净。
const logger = require('some-logger-library');
process.on('SIGTERM', async () => {
try {
await logger.flush();
console.log('日志已清空。');
process.exit(0);
} catch (err) {
console.error('清空日志时出错:', err);
process.exit(1);
}
});
6. 优雅地退出程序
一旦所有清理任务完成,使用 process.exit()
退出进程。使用退出代码来表明终止的原因:
- 0 :正常终止,
- 1 :未处理的异常,或者其他错误。
process.on('SIGTERM', async () => {
try {
await cleanUpTasks();
console.log('程序已优雅地关闭。');
process.exit(0);
} catch (err) {
console.error('关闭时出错:', err);
process.exit(1);
}
});
7. 测试关机流程
在受控环境中模拟终止信号的环境,以确保您的应用程序按预期关闭。
- 这里可以使用:
发送 SIGTERM 信号给 <进程ID>
- 在 Docker 里做某事:
运行命令 docker stop <container_id>
来停止容器。请将 <container_id>
替换为实际的容器ID。
下面是一个优雅地关闭的实现方式的例子:
const express = require('express');
const mongoose = require('mongoose');
const app = express();
// 中间件处理
app.get('/', (req, res) => res.send('Hello, World!'));
// 服务器在端口3000上运行
const server = app.listen(3000, () => {
console.log('服务器在端口3000上运行');
});
// 关闭开始...
const shutdown = async () => {
console.log('关闭开始...');
try {
server.close(() => console.log('收到HTTP服务器关闭通知'));
await mongoose.connection.close();
console.log('MongoDB连接已断开.');
process.exit(0);
} catch (err) {
console.error('关闭过程中发生错误:', err);
process.exit(1);
}
};
// 监听终止信号(SIGTERM和SIGINT)
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
最后的想法.
优雅关机不仅是一种最佳实践,更是保证应用程序在生产环境中可靠且用户友好的必备条件。通过处理终止信号、管理资源并确保所有正在进行的请求都能顺利完成,你将创建一个能够应对现代生产环境动态需求的健壮应用程序。
你可能也对这个感兴趣:
1) 怎样提升网站性能?
5) AI能改变交易市场吗?
你有什么自己处理休息时间的方法吗?下面留言分享一下吧!
关注我哦**[领英**](https://www.linkedin.com/in/arunangshu-das/)
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章