正常关机

您的应用将在其整个生命周期中重启几次,无论是在部署中还是更糟糕的情况,应用崩溃。

但在重启时,用户可能面临两个问题:

  • 一段停机时间,服务器返回到“503服务不可用”响应
  • 一个失败请求,如果重启时请求正在进行
    使用PM2群集模式和重载操作可以避免停机时间段

正常关机并重启可以避免失败请求。 本教程将向您介绍如何实现它。

正常关机

在一次正常关机时,您的应用必须经过5个步骤:

  • 收到通知停止
  • 要求负载均衡器停止接收请求
  • 完成所有正在进行的请求
  • 释放所有资源(数据库,队列…)
  • 退出
    假设我们有以下express应用:
  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. const server = require('http').createServer(app)
  5. server.listen(port, () => {
  6. console.log('Express server listening on port ' + server.address().port)
  7. })

我们首先需要拦截 SIGINT信号(由 pm2 stop发出):

  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. const server = require('http').createServer(app)
  5. server.listen(port, () => {
  6. console.log('Express server listening on port ' + server.address().port)
  7. })
  8. process.on('SIGINT', () => {
  9. console.info('SIGINT signal received.')
  10. })

然后,我们要求HTTP服务器停止接收请求并完成正在进行的请求:

  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. const server = require('http').createServer(app)
  5. server.listen(port, () => {
  6. console.log('Express server listening on port ' + server.address().port)
  7. })
  8. process.on('SIGINT', () => {
  9. console.info('SIGINT signal received.')
  10. // Stops the server from accepting new connections and finishes existing connections.
  11. server.close(function(err) {
  12. if (err) {
  13. console.error(err)
  14. process.exit(1)
  15. }
  16. })
  17. })

最后,我们关闭所有资源的连接:

  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. const server = require('http').createServer(app)
  5. server.listen(port, () => {
  6. console.log('Express server listening on port ' + server.address().port)
  7. })
  8. process.on('SIGINT', () => {
  9. console.info('SIGINT signal received.')
  10. // Stops the server from accepting new connections and finishes existing connections.
  11. server.close(function(err) {
  12. // if error, log and exit with error (1 code)
  13. if (err) {
  14. console.error(err)
  15. process.exit(1)
  16. }
  17. // close your database connection and exit with success (0 code)
  18. // for example with mongoose
  19. mongoose.connection.close(function () {
  20. console.log('Mongoose connection disconnected')
  21. process.exit(0)
  22. })
  23. })
  24. })

超时终止

默认情况下,如果应用不自行退出,PM2在发送SIGKILL信号之前会等待1600毫秒。

您可以在您的ecos.config.js中以毫秒为单位更改此值:

  1. module.exports = {
  2. apps: [{
  3. name: "app",
  4. script: "./app.js",
  5. kill_timeout: 1600,
  6. }]
  7. }

windows的正常关机

当信号不可用时,您的进程将被终止。 在这种情况下,您需要遵从 shutdown事件:

  1. process.on('message', (msg) => {
  2. if (msg == 'shutdown') {
  3. console.log('Closing all connections...')
  4. setTimeout(() => {
  5. console.log('Finished closing connections')
  6. process.exit(0)
  7. }, 1500)
  8. }
  9. })

正常启动

在提供HTTP请求之前,您的应用通常需要连接到您的数据库或其他资源。

您的应用需经过这3个步骤来避免错误:

  • 打开数据库连接
  • 开始请求一个端口
  • 通知PM2应用已准备就绪
    首先,在您的ecos.config.js中启用PM2中的 ready信号:
  1. module.exports = {
  2. apps : [{
  3. name: "api",
  4. script: "./api.js",
  5. wait_ready: true,
  6. listen_timeout: 3000,
  7. }],
  8. }

默认情况下,在3000毫秒后,PM2会考虑准备好您的应用。 使用 listen_timeout值更改此值。

让我们继续使用之前的express app:

  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. server.listen(port, () => {
  5. console.log('Express server listening on port ' + server.address().port)
  6. })
  7. ...

首先,等待数据库连接准备就绪:

  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. const server = require('http').createServer(app)
  5. mongoose.connect('mongodb://mongosA:27501,mongosB:27501', (err) => {
  6. server.listen(port, () => {
  7. console.log('Express server listening on port ' + server.address().port)
  8. })
  9. })
  10. ...

最后,使用 process.send('ready')通知PM2应用已准备好:

  1. const app = express()
  2. const port = process.env.port || 8000
  3. app.get('/', (req, res) => { res.end('Hello world') })
  4. const server = require('http').createServer(app)
  5. mongoose.connect('mongodb://mongosA:27501,mongosB:27501', (err) => {
  6. server.listen(port, () => {
  7. console.log('Express server listening on port ' + server.address().port)
  8. process.send('ready')
  9. })
  10. })
  11. ...

群集模式下的正常启动

在群集模式下,有一个默认系统,可在应用接受连接时设置每个群集。 还有一个超时时间,默认为3000毫秒,您可以使用生态系统文件中的listen_timeout属性进行设置。

原文: https://pm2.io/doc/zh/runtime/best-practices/graceful-shutdown/