mirror of
https://github.com/unraid/api.git
synced 2026-01-05 16:09:49 -06:00
fix: make clustering optional
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -60,3 +60,6 @@ test/__temp__/*
|
||||
|
||||
# Built files
|
||||
dist
|
||||
|
||||
# Typescript
|
||||
typescript
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
128
cluster.js
Normal 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
143
index.js
@@ -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
82
package-lock.json
generated
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user