使用nodemon和express优雅关闭

Tax*_*xel 7 node.js express nodemon

当 nodemon 重新启动我的 Express 服务器时,我正在努力拦截信号。我需要这个来关闭数据库,否则当我下次尝试使用它时会抛出错误。编辑:它起初看起来并不像它,但当我通过 Ctrl+C 终止它时,它确实调用了一些函数。我已经评论了哪些。

显然,nodemon 在重新启动时会发送 SIGUSR2 信号,但我尝试向该事件以及无数其他事件添加一个事件;这是文件 nodemon 被告知启动的摘录(应用程序的主入口点位于名为 的文件中/bin/www,这是我创建 Express 应用程序时的默认设置);正如你所看到的,我尝试了很多事情:

var app = require("../app");
var debug = require("debug")("server:server");
var http = require("http");
// terminus was built to handle this, right?
const { createTerminus } = require("@godaddy/terminus");


app.set("port", "3001");

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

// the terminus handler for SIGUSR2
function onSignal() {
    console.log("server is starting cleanup");
    // start cleanup of resource, like databases or file descriptors
}

async function onHealthCheck() {
    // checks if the system is healthy, like the db connection is live
    // resolves, if health, rejects if not
    return true;
}

createTerminus(server, {
    signal: "SIGUSR2",
    healthChecks: { "/healthcheck": onHealthCheck },
    onSignal
});

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on("error", onError);
server.on("listening", onListening);
server.on("close", () => {
    // this is never called on nodemon restart, it is when ctrl+c is pressed
    console.log("Server close");
});



/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
    var addr = server.address();
    var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
    debug("Listening on " + bind);
}



process.on("SIGTERM", function() {
    // this is never called
    console.log("SIGTERM");        
    server.close(function() {
        process.exit(0);
    });
});
process.on("SIGINT", function() {
    // this is only called on ctrl+c, not restart
    console.log("SIGINT");
    server.close(function() {
        process.exit(0);
    });
});
process.on("SIGUSR2", function() {
    // never called
    console.log("SIGUSR2");
    server.close(function() {
        process.exit(0);
    });
});
process.on("beforeExit", () => {
    // nope, never called
    console.log("before exit");
});
process.on("exit", () => {
    // only called on ctrl+c, not on restart
    console.log("exit");
});
Run Code Online (Sandbox Code Playgroud)

我非常确定这些函数中至少有一个应该处理该事件并允许我关闭数据库,但是如果我通过以下方式启动服务器,nodemon /bin/www我只会得到与启动相关的输出,如果我然后通过输入 重新启动服务器rs,输出日志看起来像这样:

Started directory watcher //normal startup
rs
[nodemon] starting `node ./bin/www` //none of the functions above is called
Run Code Online (Sandbox Code Playgroud)

Sar*_*rah 0

您可以为 nodemon 状态更改设置事件侦听器。因此,您可以让它在重新启动时运行 SQL 查询来终止应用程序的所有进程。

我遇到了同样的问题,并在数据库中创建了一个名为kill_other_processes的过程,并让nodemon在重新启动时调用它。

首先,在根目录中为 nodemon 创建一个名为nodemon.json的配置文件,其中包含以下内容:

{
  "events": {
    "restart": "mysql --user=username --password=password -Bse \"USE your_database; CALL kill_other_processes();\""
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,在数据库中创建过程kill_other_processes (来自此答案,或您选择结束连接的任何其他查询):

DROP PROCEDURE IF EXISTS kill_other_processes;

DELIMITER $$

CREATE PROCEDURE kill_other_processes()
BEGIN
  DECLARE finished INT DEFAULT 0;
  DECLARE proc_id INT;
  DECLARE proc_id_cursor CURSOR FOR SELECT id FROM information_schema.processlist;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;

  OPEN proc_id_cursor;
  proc_id_cursor_loop: LOOP
    FETCH proc_id_cursor INTO proc_id;

    IF finished = 1 THEN 
      LEAVE proc_id_cursor_loop;
    END IF;

    IF proc_id <> CONNECTION_ID() THEN
      KILL proc_id;
    END IF;

  END LOOP proc_id_cursor_loop;
  CLOSE proc_id_cursor;
END$$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

现在,nodemon 将在每次重新启动时终止连接。