From 53b14f4820d6ee57002645ba1c67b0068a876ffb Mon Sep 17 00:00:00 2001 From: Matt Sergeant Date: Sat, 20 May 2017 19:39:01 -0400 Subject: [PATCH 1/3] Set graceful shutdown off by default Still allow haraka -c --graceful Also sets graceful shutdown to shutdown in max 2xChildren amount of time it sets to shutdown. --- configfile.js | 1 + server.js | 25 ++++++++++++++++--------- tls_socket.js | 4 ++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/configfile.js b/configfile.js index 90301ffc5..10ea16051 100644 --- a/configfile.js +++ b/configfile.js @@ -266,6 +266,7 @@ cfreader.ensure_enoent_timer = function () { })(files[i]); // END BLOCK SCOPE } }, 60 * 1000); + cfreader._enoent_timer.unref(); }; process.on('message', function (msg) { diff --git a/server.js b/server.js index aaf250ddd..ddaac2fdf 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,7 @@ 'use strict'; // smtp network server +// var log = require('why-is-node-running'); var net = require('./tls_socket'); var conn = require('./connection'); var outbound = require('./outbound'); @@ -27,6 +28,7 @@ Server.load_smtp_ini = function () { Server.cfg = Server.config.get('smtp.ini', { booleans: [ '-main.daemonize', + '-main.graceful_shutdown', ], }, function () { Server.load_smtp_ini(); @@ -98,25 +100,28 @@ Server.gracefulRestart = function () { } Server.gracefulShutdown = function () { + if (!Server.cfg.main.graceful_shutdown) { + logger.loginfo("Shutting down."); + process.exit(0); + } logger.loginfo('Shutting down listeners'); Server.listeners.forEach(function (server) { server.close(); }); Server._graceful(function () { + // log(); logger.loginfo("Failed to shutdown naturally. Exiting."); process.exit(0); }); } Server._graceful = function (shutdown) { - if (!Server.cluster) { - if (shutdown) { - ['outbound', 'cfreader', 'plugins'].forEach(function (module) { - process.emit('message', {event: module + '.shutdown'}); - }); - var t = setTimeout(shutdown, Server.cfg.main.force_shutdown_timeout * 1000); - return t.unref(); - } + if (!Server.cluster && shutdown) { + ['outbound', 'cfreader', 'plugins'].forEach(function (module) { + process.emit('message', {event: module + '.shutdown'}); + }); + var t = setTimeout(shutdown, Server.cfg.main.force_shutdown_timeout * 1000); + return t.unref(); } if (gracefull_in_progress) { @@ -132,7 +137,9 @@ Server._graceful = function (shutdown) { // only reload one worker at a time // otherwise, we'll have a time when no connection handlers are running var worker_ids = Object.keys(cluster.workers); - async.eachSeries(worker_ids, function (id, cb) { + var limit = worker_ids.length - 1; + if (limit < 2) limit = 1; + async.eachLimit(worker_ids, limit, function (id, cb) { logger.lognotice("Killing node: " + id); var worker = cluster.workers[id]; ['outbound', 'cfreader', 'plugins'].forEach(function (module) { diff --git a/tls_socket.js b/tls_socket.js index 46111d3b2..3ac8d533b 100644 --- a/tls_socket.js +++ b/tls_socket.js @@ -137,6 +137,10 @@ pluggableStream.prototype.setKeepAlive = function (bool) { pluggableStream.prototype.setNoDelay = function (/* true||false */) { }; +pluggableStream.prototype.unref = function () { + return this.targetsocket.unref(); +}; + pluggableStream.prototype.setTimeout = function (timeout) { this._timeout = timeout; return this.targetsocket.setTimeout(timeout); From 1c570a02de6cedc9d2ab8d3bdf03dfe3ae441a37 Mon Sep 17 00:00:00 2001 From: Matt Sergeant Date: Sun, 21 May 2017 15:12:14 -0400 Subject: [PATCH 2/3] Allow gracefulShutdown() to always be graceful Makes the tests pass --- haraka.js | 4 ++-- server.js | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/haraka.js b/haraka.js index d2b5b7b4e..8decebfcc 100644 --- a/haraka.js +++ b/haraka.js @@ -50,10 +50,10 @@ var shutting_down = false; logger.lognotice(sig + ' received'); logger.dump_and_exit(function () { if (server.cluster && server.cluster.isMaster) { - server.gracefulShutdown(); + server.performShutdown(); } else if (!server.cluster) { - server.gracefulShutdown(); + server.performShutdown(); } }); }); diff --git a/server.js b/server.js index ddaac2fdf..033ce77f3 100644 --- a/server.js +++ b/server.js @@ -99,11 +99,15 @@ Server.gracefulRestart = function () { Server._graceful(); } -Server.gracefulShutdown = function () { - if (!Server.cfg.main.graceful_shutdown) { - logger.loginfo("Shutting down."); - process.exit(0); +Server.performShutdown = function () { + if (Server.cfg.main.graceful_shutdown) { + return Server.gracefulShutdown(); } + logger.loginfo("Shutting down."); + process.exit(0); +} + +Server.gracefulShutdown = function () { logger.loginfo('Shutting down listeners'); Server.listeners.forEach(function (server) { server.close(); From b1a9eea10ecd9933d51aa0fec6f6ab6f88a1cec7 Mon Sep 17 00:00:00 2001 From: Matt Sergeant Date: Sun, 21 May 2017 15:21:22 -0400 Subject: [PATCH 3/3] Fix comment --- server.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 033ce77f3..fc145631f 100644 --- a/server.js +++ b/server.js @@ -138,8 +138,9 @@ Server._graceful = function (shutdown) { var disconnect_timeout = 30; var exit_timeout = 30; cluster.removeAllListeners('exit'); - // only reload one worker at a time - // otherwise, we'll have a time when no connection handlers are running + // we reload using eachLimit where limit = num_workers - 1 + // this kills all-but-one workers in parallel, leaving one running + // for new connections, and then restarts that one last worker. var worker_ids = Object.keys(cluster.workers); var limit = worker_ids.length - 1; if (limit < 2) limit = 1;