fix: make clustering optional

This commit is contained in:
Alexis Tyler
2020-09-11 18:13:06 +09:30
parent 55111679af
commit 5b96a740fa
6 changed files with 204 additions and 158 deletions

3
.gitignore vendored
View File

@@ -60,3 +60,6 @@ test/__temp__/*
# Built files
dist
# Typescript
typescript

View File

@@ -263,11 +263,11 @@ class FuncDirective extends SchemaDirectiveVisitor {
// Allow fields to be extracted
if (directiveArgs.extractFromResponse) {
const extractedField = get(result, directiveArgs.extractFromResponse);
log.debug(pluginOrModule, pluginOrModuleName, 'Result:', extractedField);
log.debug(pluginOrModule, pluginOrModuleName, 'Result:', JSON.stringify(extractedField));
return extractedField;
}
log.debug(pluginOrModule, pluginOrModuleName, 'Result:', result);
log.debug(pluginOrModule, pluginOrModuleName, 'Result:', JSON.stringify(result));
return result;
};
}

View File

@@ -58,7 +58,7 @@ export const run = async (channel: string, mutation: string, options: RunOptions
return resolve(moduleToRun(context));
});
log.debug('Module:', moduleToRun.name, 'Result:', result.json);
// log.debug('Module:', moduleToRun.name, 'Result:', result.json);
// Save result
publish(channel, mutation, result.json);

128
cluster.js Normal file
View File

@@ -0,0 +1,128 @@
// @ts-check
const path = require('path');
const cluster = require('cluster');
const log = process.env.NODE_ENV === 'production' ? {
info() { },
log() { },
debug() { },
error() { }
} : console;
// Set current working directory
process.chdir(__dirname);
const RESTART_ATTEMPTS = 10;
let currentRestartAttempt = 0;
let currentWorker;
let restart = true;
// @see https://github.com/nodejs/node-v0.x-archive/blob/master/doc/api/process.markdown#exit-codes
const onWorkerExit = (_, code) => {
if (!restart) {
process.exit(0);
}
// Worker killed itself and doesn't want to be restarted
if (code === 130) {
log.debug(`Worker killed itself intentially. Exiting.`);
process.exit(130);
}
// Reload worker
if (code === null || code === 0) {
const newWorker = cluster.fork();
newWorker.once('online', () => {
currentRestartAttempt = 0;
currentWorker = newWorker;
});
return;
}
// Too many restarts, kill process
if (currentRestartAttempt >= RESTART_ATTEMPTS) {
log.debug(`No restart attempts left. Exiting.`);
process.exit(1);
}
// Known error restart worker
currentRestartAttempt++;
currentWorker = cluster.fork();
};
// Master
if (cluster.isMaster) {
// Set process name
process.title = 'gql-supervisor';
log.info(`<master> pid = ${process.pid}`);
currentWorker = cluster.fork();
cluster.on('exit', onWorkerExit);
// Allow reload on SIGHUP
process.on('SIGHUP', () => {
log.debug('<master> Reloading worker');
currentWorker.send('shutdown');
});
// Toggle debug logs
process.on('SIGUSR2', () => {
log.debug('<master> Updating log level.');
currentWorker.send('SIGUSR2');
});
// Kill all workers then exit gracefully
process.on('SIGTERM', () => {
log.info(`Killing worker`);
restart = false;
currentWorker.send('shutdown');
});
}
// Worker
if (cluster.isWorker) {
log.info(`<worker> pid = ${process.pid}`);
const isMissingMainFile = (error) => {
// Other error
if (error.code !== 'MODULE_NOT_FOUND') {
return false;
}
// Missing file but it's multiple levels deep
// This likely isn't main
if (error.requireStack.length >= 2) {
return false;
}
// It's a single require but for another file
if (error.requireStack[0] !== __filename) {
return false;
}
return true;
};
// @ts-ignore
const package = require('./package.json');
const { main } = package;
if (!main) {
log.error('<worker> Missing main field in package.json');
process.exit(1);
}
const mainPath = path.resolve(__dirname, main);
try {
log.info('<worker> loaded');
require(mainPath);
} catch (error) {
if (isMissingMainFile(error)) {
log.error(`<worker> Missing main file "${mainPath}".`);
process.exit(130);
}
log.error(error);
}
}

143
index.js
View File

@@ -1,5 +1,7 @@
// @ts-check
const path = require('path');
const cluster = require('cluster');
const package = require('./package.json');
const { main } = package;
const log = process.env.NODE_ENV === 'production' ? {
info() { },
@@ -8,131 +10,26 @@ const log = process.env.NODE_ENV === 'production' ? {
error() { }
} : console;
// Set current working directory
process.chdir(__dirname);
const RESTART_ATTEMPTS = 10;
let currentRestartAttempt = 0;
let currentWorker;
let restart = true;
// @see https://github.com/nodejs/node-v0.x-archive/blob/master/doc/api/process.markdown#exit-codes
const onWorkerExit = (_, code) => {
if (!restart) {
process.exit(0);
}
// Worker killed itself and doesn't want to be restarted
if (code === 130) {
log.debug(`Worker killed itself intentially. Exiting.`);
process.exit(130);
}
// Reload worker
if (code === null || code === 0) {
const newWorker = cluster.fork();
newWorker.once('online', () => {
currentRestartAttempt = 0;
currentWorker = newWorker;
});
return;
}
// Too many restarts, kill process
if (currentRestartAttempt >= RESTART_ATTEMPTS) {
log.debug(`No restart attempts left. Exiting.`);
process.exit(1);
}
// Known error restart worker
currentRestartAttempt++;
currentWorker = cluster.fork();
};
// Master
if (cluster.isMaster) {
// Set process name
process.title = 'gql-supervisor';
// Show real stack trace in development
if (process.env.NODE_ENV === 'development') {
try {
require('source-map-support').install({
handleUncaughtExceptions: false
});
} catch {
log.error(`Could not load "source-map-support", do you have it installed?`);
}
}
log.info(`<master> pid = ${process.pid}`);
currentWorker = cluster.fork();
cluster.on('exit', onWorkerExit);
// Allow reload on SIGHUP
process.on('SIGHUP', () => {
log.debug('<master> Reloading worker');
currentWorker.send('shutdown');
});
// Toggle debug logs
process.on('SIGUSR2', () => {
log.debug('<master> Updating log level.');
currentWorker.send('SIGUSR2');
});
// Kill all workers then exit gracefully
process.on('SIGTERM', () => {
log.info(`Killing worker`);
restart = false;
currentWorker.send('shutdown');
});
if (!main) {
log.error('<worker> Missing main field in package.json');
process.exit(1);
}
// Worker
if (cluster.isWorker) {
log.info(`<worker> pid = ${process.pid}`);
const isMissingMainFile = (error) => {
// Other error
if (error.code !== 'MODULE_NOT_FOUND') {
return false;
}
// Missing file but it's multiple levels deep
// This likely isn't main
if (error.requireStack.length >= 2) {
return false;
}
// It's a single require but for another file
if (error.requireStack[0] !== __filename) {
return false;
}
return true;
}
// @ts-ignore
const package = require('./package.json');
const { main } = package;
if (!main) {
log.error('<worker> Missing main field in package.json');
process.exit(1);
}
const mainPath = path.resolve(__dirname, main);
const mainPath = path.resolve(__dirname, main);
// Show real stack trace in development
if (process.env.NODE_ENV === 'development') {
try {
log.info('<worker> loaded');
require(mainPath);
} catch (error) {
if (isMissingMainFile(error)) {
log.error(`<worker> Missing main file "${mainPath}".`);
process.exit(130);
}
log.error(error);
require('source-map-support').install({
handleUncaughtExceptions: false
});
} catch {
log.error(`Could not load "source-map-support", do you have it installed?`);
}
}
if (!process.env.CLUSTER) {
require(mainPath);
} else {
require('./cluster');
}

82
package-lock.json generated
View File

@@ -1223,7 +1223,7 @@
}
},
"@unraid/core": {
"version": "github:unraid/core#8c8d0f18ddc7dfd39716f0fc8e54620c7cca6dd9",
"version": "github:unraid/core#7241bb2f92301613f6de94591ef91ded54428467",
"from": "github:unraid/core",
"requires": {
"accesscontrol": "^2.2.1",
@@ -2248,9 +2248,9 @@
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
},
"babel-eslint": {
"version": "10.1.0",
@@ -2402,9 +2402,9 @@
}
},
"bl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
"integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
@@ -6418,9 +6418,9 @@
},
"dependencies": {
"bl": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
"integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
"integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
"requires": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
@@ -7979,9 +7979,9 @@
},
"dependencies": {
"type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz",
"integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow=="
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz",
"integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA=="
}
}
},
@@ -8925,9 +8925,9 @@
},
"dependencies": {
"@types/node": {
"version": "9.6.57",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.57.tgz",
"integrity": "sha512-588MBlPWKeJFshLmnYbqMEaM3NaJFCVZFgpQ5rQxKCVXMNw2Gs7sTORvCDlaPBP6AabiIvmd22eT9fcIvTeZUw=="
"version": "9.6.58",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.58.tgz",
"integrity": "sha512-I5B2ZIvr5G5qW6VUZgMk284p/41/U5x3Lqyz3Hz9va3bmxgV7p5CBnDPGv/lGFgGDP4415pqZXLsa4cKA3BHAg=="
}
}
},
@@ -11871,17 +11871,25 @@
}
},
"mqtt-packet": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.3.2.tgz",
"integrity": "sha512-i56+2kN6F57KInGtjjfUXSl4xG8u/zOvfaXFLKFAbBXzWkXOmwcmjaSCBPayf2IQCkQU0+h+S2DizCo3CF6gQA==",
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.6.0.tgz",
"integrity": "sha512-LvghnKMFC70hKWMVykmhJarlO5e7lT3t9s9A2qPCUx+lazL3Mq55U+eCV0eLi7/nRRQYvEUWo/2tTo89EjnCJQ==",
"requires": {
"bl": "^1.2.2",
"bl": "^4.0.2",
"debug": "^4.1.1",
"inherits": "^2.0.3",
"process-nextick-args": "^2.0.0",
"safe-buffer": "^5.1.2"
"process-nextick-args": "^2.0.1"
},
"dependencies": {
"bl": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
"integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
"requires": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
@@ -11889,6 +11897,16 @@
"requires": {
"ms": "^2.1.1"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
@@ -15772,9 +15790,9 @@
}
},
"split2": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/split2/-/split2-3.1.1.tgz",
"integrity": "sha512-emNzr1s7ruq4N+1993yht631/JH+jaj0NYBosuKmLcq+JkGQ9MmTw1RB1fGaTCzUuseRIClrlSLHRNYGwWQ58Q==",
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
"integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
"requires": {
"readable-stream": "^3.0.0"
},
@@ -15804,9 +15822,9 @@
},
"dependencies": {
"@types/node": {
"version": "9.6.57",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.57.tgz",
"integrity": "sha512-588MBlPWKeJFshLmnYbqMEaM3NaJFCVZFgpQ5rQxKCVXMNw2Gs7sTORvCDlaPBP6AabiIvmd22eT9fcIvTeZUw=="
"version": "9.6.58",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.58.tgz",
"integrity": "sha512-I5B2ZIvr5G5qW6VUZgMk284p/41/U5x3Lqyz3Hz9va3bmxgV7p5CBnDPGv/lGFgGDP4415pqZXLsa4cKA3BHAg=="
}
}
},
@@ -16370,9 +16388,9 @@
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"systeminformation": {
"version": "4.26.10",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.26.10.tgz",
"integrity": "sha512-bO4FIzrjESAfh4KHwkUJym3jvKtJ4oJ2PG0BBQGBmKa0pF2oanpkB7CF4ZsSX7vfp3+GKaLzioVwpV/3Tyk+lQ=="
"version": "4.27.3",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.27.3.tgz",
"integrity": "sha512-0Nc8AYEK818h7FI+bbe/kj7xXsMD5zOHvO9alUqQH/G4MHXu5tHQfWqC/bzWOk4JtoQPhnyLgxMYncDA2eeSBw=="
},
"table": {
"version": "5.4.6",