diff --git a/CHANGELOG.md b/CHANGELOG.md index 06115027..13a52cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Add option to use [Nunjucks](https://mozilla.github.io/nunjucks/) templates in modules. (See `helloworld` module as an example.) - Add Bulgarian translations for MagicMirror² and Alert module +- Add graceful shutdown of modules by calling `stop` function of each `node_helper` on SIGINT before exiting. ### Updated diff --git a/js/app.js b/js/app.js index 138fec70..bfec5baf 100644 --- a/js/app.js +++ b/js/app.js @@ -236,6 +236,33 @@ var App = function() { }); }); }; + + /* stop() + * This methods stops the core app. + * This calls each node_helper's STOP() function, if it exists. + * Added to fix #1056 + */ + this.stop = function() { + for (var h in nodeHelpers) { + var nodeHelper = nodeHelpers[h]; + if (typeof nodeHelper.stop === "function") { + nodeHelper.stop(); + } + } + }; + + /* Listen for SIGINT signal and call stop() function. + * + * Added to fix #1056 + * Note: this is only used if running `server-only`. Otherwise + * this.stop() is called by app.on("before-quit"... in `electron.js` + */ + process.on("SIGINT", () => { + console.log("[SIGINT] Received. Shutting down server..."); + setTimeout(() => { process.exit(0); }, 3000); // Force quit after 3 seconds + this.stop(); + process.exit(0); + }); }; module.exports = new App(); diff --git a/js/electron.js b/js/electron.js index 84842ed2..fc6ab98e 100644 --- a/js/electron.js +++ b/js/electron.js @@ -96,6 +96,20 @@ app.on("activate", function() { } }); +/* This method will be called when SIGINT is received and will call + * each node_helper's stop function if it exists. Added to fix #1056 + * + * Note: this is only used if running Electron. Otherwise + * core.stop() is called by process.on("SIGINT"... in `app.js` + */ +app.on("before-quit", (event) => { + console.log("Shutting down server..."); + event.preventDefault(); + setTimeout(() => { process.exit(0); }, 3000); // Force-quit after 3 seconds. + core.stop(); + process.exit(0); +}); + // Start the core application if server is run on localhost // This starts all node helpers and starts the webserver. if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) > -1) { diff --git a/modules/README.md b/modules/README.md index 12a42e59..76973996 100644 --- a/modules/README.md +++ b/modules/README.md @@ -555,6 +555,17 @@ start: function() { } ```` +#### `stop()` +This method is called when the MagicMirror server receives a `SIGINT` command and is shutting down. This method should include any commands needed to close any open connections, stop any sub-processes and gracefully exit the module. + +**Example:** +````javascript +stop: function() { + console.log("Shutting down MyModule"); + this.connection.close(); +} +```` + #### `socketNotificationReceived: function(notification, payload)` With this method, your node helper can receive notifications from your modules. When this method is called, it has 2 arguments: diff --git a/modules/node_modules/node_helper/index.js b/modules/node_modules/node_helper/index.js index 37c3e2cb..7a8818be 100644 --- a/modules/node_modules/node_helper/index.js +++ b/modules/node_modules/node_helper/index.js @@ -23,6 +23,17 @@ NodeHelper = Class.extend({ console.log("Starting module helper: " + this.name); }, + /* stop() + * Called when the MagicMirror server receives a `SIGINT` + * Close any open connections, stop any sub-processes and + * gracefully exit the module. + * + */ + stop: function() { + console.log("Stopping module helper: " + this.name); + }, + + /* socketNotificationReceived(notification, payload) * This method is called when a socket notification arrives. *