implemented kill/restart functionality

This commit is contained in:
Daniel Sommer 2022-03-18 13:56:19 +01:00
parent 739c52fc84
commit daeb9d004e
3 changed files with 39 additions and 19 deletions

View file

@ -13,16 +13,20 @@
"method": "get", "method": "get",
"command": "tail", "command": "tail",
"args": [ "args": [
"-f", "/tmp/test" "-f",
"/tmp/test"
], ],
"detach": true "options": {
"detach": true,
"unique": true,
"restart": true
}
}, },
{ {
"url": "/uptime", "url": "/uptime",
"method": "get", "method": "get",
"command": "uptime", "command": "uptime",
"args": [ "args": []
]
} }
] ]
} }

View file

@ -1,5 +1,5 @@
const logger = require('./logger.js'); const logger = require('./logger.js');
const { spawn } = require('child_process') const { spawn } = require('child_process');
const cmds = new Map(); const cmds = new Map();
@ -7,9 +7,13 @@ async function execute(endpoint) {
if (endpoint === undefined) { if (endpoint === undefined) {
return; return;
} }
if (isCommandActive(endpoint)) { if (endpoint.options?.unique && isCommandActive(endpoint)) {
logger.info('not executing command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') because it is already active'); if (!endpoint.options?.restart) {
throw new Error('command is already active'); logger.info('not executing unique command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') because it is already active');
throw new Error('command is already active');
}
logger.info('killing and restarting unique command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')');
await killCommand(endpoint);
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logger.info('executing command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')...'); logger.info('executing command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')...');
@ -26,18 +30,21 @@ async function execute(endpoint) {
cmd.on('spawn', () => { cmd.on('spawn', () => {
logger.info('spawned command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')'); logger.info('spawned command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')');
addCommand(cmd, endpoint); addCommand(cmd, endpoint);
if (endpoint.detach === true) { if (endpoint.options?.detach) {
resolve(); resolve();
} }
}); });
cmd.on('error', (err) => { cmd.on('error', (err) => {
error += err; error += err;
removeCommand(endpoint); removeCommand(endpoint);
if (endpoint.detach === true) { if (endpoint.options?.detach) {
reject(); reject();
} }
}); });
cmd.on('close', (code) => { cmd.on('exit', (code) => {
if (code === null) {
code = 0;
}
removeCommand(endpoint); removeCommand(endpoint);
let fn = logger.info; let fn = logger.info;
let msg = 'command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') finished with exit code ' + code + ' after ' + (new Date().getTime() - cmd.timestamp) + 'ms'; let msg = 'command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') finished with exit code ' + code + ' after ' + (new Date().getTime() - cmd.timestamp) + 'ms';
@ -61,29 +68,38 @@ function addCommand(command, endpoint) {
if (command === undefined || endpoint === undefined) { if (command === undefined || endpoint === undefined) {
return; return;
} }
cmds.set(JSON.stringify(endpoint), command); cmds.set(endpoint, command);
} }
function removeCommand(endpoint) { function removeCommand(endpoint) {
if (endpoint === undefined) { if (endpoint === undefined) {
return; return;
} }
cmds.delete(JSON.stringify(endpoint)); cmds.delete(endpoint);
} }
function isCommandActive(endpoint) { function isCommandActive(endpoint) {
return endpoint !== undefined && cmds.has(JSON.stringify(endpoint)); return endpoint !== undefined && cmds.has(endpoint);
} }
function killCommand(endpoint) { async function killCommand(endpoint) {
if (endpoint === undefined) { if (endpoint === undefined) {
return; return;
} }
const command = cmds.get(JSON.stringify(endpoint)); const command = cmds.get(endpoint);
if (command === undefined) { if (command === undefined) {
return; return;
} }
process.kill(command.pid); process.kill(command.pid, 'SIGINT');
while(isCommandActive(endpoint)) {
await sleep(100);
}
}
async function sleep(milliseconds) {
return new Promise((resolve, reject) => {
setTimeout(resolve, milliseconds);
});
} }
module.exports = { module.exports = {

View file

@ -1,7 +1,6 @@
const logger = require('./logger.js'); const logger = require('./logger.js');
const commands = require('./commands.js'); const commands = require('./commands.js');
const http = require('http'); const http = require('http');
const { config } = require('process');
let server; let server;
let api; let api;
@ -51,6 +50,7 @@ function finishRequest(request, response, data, code) {
if (response === undefined) { if (response === undefined) {
return; return;
} }
data.time = (new Date().getTime() - request.timestamp) + 'ms';
if (code === undefined) { if (code === undefined) {
code = 200; code = 200;
} }
@ -59,7 +59,7 @@ function finishRequest(request, response, data, code) {
} else { } else {
data.status = 'error'; data.status = 'error';
} }
data.time = (new Date().getTime() - request.timestamp) + 'ms';
response.writeHead(code); response.writeHead(code);
const json = JSON.stringify(data); const json = JSON.stringify(data);
response.end(json); response.end(json);