From 1ba8403bfe4d3098090fa5e8452f3d4659169797 Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Mon, 12 Aug 2019 08:32:27 +1000 Subject: [PATCH] fix: handle cluster module not existing --- lib/clustering.js | 103 ++++++++++++++++++++---------------- package-lock.json | 72 +++++++++++++++++++++---- package.json | 1 + test/tap/no-cluster-test.js | 15 ++++++ 4 files changed, 135 insertions(+), 56 deletions(-) create mode 100644 test/tap/no-cluster-test.js diff --git a/lib/clustering.js b/lib/clustering.js index 6039d76..ca49cb5 100644 --- a/lib/clustering.js +++ b/lib/clustering.js @@ -1,18 +1,25 @@ -const cluster = require('cluster'); -const debug = require('debug')('log4js:clustering'); -const LoggingEvent = require('./LoggingEvent'); -const configuration = require('./configuration'); +const debug = require("debug")("log4js:clustering"); +const LoggingEvent = require("./LoggingEvent"); +const configuration = require("./configuration"); + +let disabled = false; +let cluster = null; +try { + cluster = require("cluster"); //eslint-disable-line +} catch (e) { + debug("cluster module not present"); + disabled = true; +} const listeners = []; -let disabled = false; let pm2 = false; -let pm2InstanceVar = 'NODE_APP_INSTANCE'; +let pm2InstanceVar = "NODE_APP_INSTANCE"; -const isPM2Master = () => pm2 && process.env[pm2InstanceVar] === '0'; +const isPM2Master = () => pm2 && process.env[pm2InstanceVar] === "0"; const isMaster = () => disabled || cluster.isMaster || isPM2Master(); -const sendToListeners = (logEvent) => { +const sendToListeners = logEvent => { listeners.forEach(l => l(logEvent)); }; @@ -20,58 +27,64 @@ const sendToListeners = (logEvent) => { // process.send const receiver = (worker, message) => { // prior to node v6, the worker parameter was not passed (args were message, handle) - debug('cluster message received from worker ', worker, ': ', message); + debug("cluster message received from worker ", worker, ": ", message); if (worker.topic && worker.data) { message = worker; worker = undefined; } - if (message && message.topic && message.topic === 'log4js:message') { - debug('received message: ', message.data); + if (message && message.topic && message.topic === "log4js:message") { + debug("received message: ", message.data); const logEvent = LoggingEvent.deserialise(message.data); sendToListeners(logEvent); } }; -configuration.addListener((config) => { - // clear out the listeners, because configure has been called. - listeners.length = 0; +if (!disabled) { + configuration.addListener(config => { + // clear out the listeners, because configure has been called. + listeners.length = 0; - ({ pm2, disableClustering:disabled, pm2InstanceVar='NODE_APP_INSTANCE' } = config); + ({ + pm2, + disableClustering: disabled, + pm2InstanceVar = "NODE_APP_INSTANCE" + } = config); - debug(`clustering disabled ? ${disabled}`); - debug(`cluster.isMaster ? ${cluster.isMaster}`); - debug(`pm2 enabled ? ${pm2}`); - debug(`pm2InstanceVar = ${pm2InstanceVar}`); - debug(`process.env[${pm2InstanceVar}] = ${process.env[pm2InstanceVar]}`); + debug(`clustering disabled ? ${disabled}`); + debug(`cluster.isMaster ? ${cluster && cluster.isMaster}`); + debug(`pm2 enabled ? ${pm2}`); + debug(`pm2InstanceVar = ${pm2InstanceVar}`); + debug(`process.env[${pm2InstanceVar}] = ${process.env[pm2InstanceVar]}`); - // just in case configure is called after shutdown - if (pm2) { - process.removeListener('message', receiver); - } - if (cluster.removeListener) { - cluster.removeListener('message', receiver); - } + // just in case configure is called after shutdown + if (pm2) { + process.removeListener("message", receiver); + } + if (cluster && cluster.removeListener) { + cluster.removeListener("message", receiver); + } - if (config.disableClustering) { - debug('Not listening for cluster messages, because clustering disabled.'); - } else if (isPM2Master()) { - // PM2 cluster support - // PM2 runs everything as workers - install pm2-intercom for this to work. - // we only want one of the app instances to write logs - debug('listening for PM2 broadcast messages'); - process.on('message', receiver); - } else if (cluster.isMaster) { - debug('listening for cluster messages'); - cluster.on('message', receiver); - } else { - debug('not listening for messages, because we are not a master process'); - } -}); + if (disabled || config.disableClustering) { + debug("Not listening for cluster messages, because clustering disabled."); + } else if (isPM2Master()) { + // PM2 cluster support + // PM2 runs everything as workers - install pm2-intercom for this to work. + // we only want one of the app instances to write logs + debug("listening for PM2 broadcast messages"); + process.on("message", receiver); + } else if (cluster.isMaster) { + debug("listening for cluster messages"); + cluster.on("message", receiver); + } else { + debug("not listening for messages, because we are not a master process"); + } + }); +} module.exports = { onlyOnMaster: (fn, notMaster) => (isMaster() ? fn() : notMaster), isMaster, - send: (msg) => { + send: msg => { if (isMaster()) { sendToListeners(msg); } else { @@ -81,10 +94,10 @@ module.exports = { worker: process.pid }; } - process.send({ topic: 'log4js:message', data: msg.serialise() }); + process.send({ topic: "log4js:message", data: msg.serialise() }); } }, - onMessage: (listener) => { + onMessage: listener => { listeners.push(listener); } }; diff --git a/package-lock.json b/package-lock.json index 4969645..ff0322f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1056,7 +1056,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -1156,7 +1156,7 @@ "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", "dev": true }, "esm": { @@ -1185,7 +1185,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -1194,7 +1194,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -1299,6 +1299,16 @@ "object-assign": "^4.0.1" } }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1524,7 +1534,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, "function-loop": { @@ -1640,7 +1650,7 @@ "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", "dev": true, "requires": { "function-bind": "^1.1.1" @@ -1846,7 +1856,7 @@ "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -1994,6 +2004,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -2438,6 +2454,12 @@ } } }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, "merge-source-map": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", @@ -2465,7 +2487,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", "dev": true }, "minimatch": { @@ -2518,6 +2540,12 @@ } } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -2851,7 +2879,7 @@ "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", "dev": true, "requires": { "p-try": "^1.0.0" @@ -3015,9 +3043,31 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", "dev": true }, + "proxyquire": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.2.tgz", + "integrity": "sha512-ovE7O5UhsDE3pBtf8YgTr+w3S0xCMYAbUAbJUbqHODB+JK1jyZnvjbSGKe54ewyyEHXc6uZfZNYhlSxYJDZQ8A==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.1", + "resolve": "^1.11.1" + }, + "dependencies": { + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -4883,7 +4933,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "~1.0.2" diff --git a/package.json b/package.json index af19655..bb8a0e1 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "husky": "^3.0.2", "nyc": "^14.1.1", "prettier": "^1.18.2", + "proxyquire": "^2.1.2", "tap": "^14.5.0", "typescript": "^3.5.3", "validate-commit-msg": "^2.14.0" diff --git a/test/tap/no-cluster-test.js b/test/tap/no-cluster-test.js new file mode 100644 index 0000000..3a4c447 --- /dev/null +++ b/test/tap/no-cluster-test.js @@ -0,0 +1,15 @@ +const { test } = require("tap"); +const proxyquire = require("proxyquire"); + +test("clustering is disabled if cluster is not present", t => { + const log4js = proxyquire("../../lib/log4js", { cluster: null }); + const recorder = require("../../lib/appenders/recording"); + log4js.configure({ + appenders: { vcr: { type: "recording" } }, + categories: { default: { appenders: ["vcr"], level: "debug" } } + }); + log4js.getLogger().info("it should still work"); + const events = recorder.replay(); + t.equal(events[0].data[0], "it should still work"); + t.end(); +});