monex
Version:
Execute one or multiple scripts, interactively or in daemon mode, and restart them whenever they crash or a watched file changes.
91 lines (90 loc) • 2.63 kB
JavaScript
/* IMPORT */
import process from 'node:process';
import pidtree from 'pidtree';
import pidusage from 'pidusage';
/* MAIN */
const PID = {
/* TREE API */
tree: {
get: async (pid) => {
try {
if (!pid)
return [];
return await pidtree(pid, { root: true });
}
catch {
return;
}
},
kill: async (pid, treeFallback = [pid]) => {
if (!pid)
return;
const pids = await PID.tree.get(pid) || treeFallback;
await Promise.all(pids.map(PID.kill));
},
usage: async (pid, treeFallback = [pid]) => {
if (!pid)
return;
const pids = await PID.tree.get(pid) || treeFallback;
const usages = (await Promise.all(pids.map(PID.usage))).filter(usage => usage); //TSC
if (!usages.length)
return;
return usages.reduce((acc, usage) => ({
cpu: acc.cpu + usage.cpu,
memory: acc.memory + usage.memory,
birthtime: acc.birthtime,
uptime: acc.uptime
}), usages[0]);
}
},
/* API */
exists: (pid) => {
try {
return process.kill(pid, 0);
}
catch (error) {
return (error instanceof Error) && ('code' in error) && (error.code === 'EPERM');
}
},
kill: async (pid) => {
if (!pid)
return;
return new Promise(async (resolve) => {
PID.signal(pid, 'SIGTERM'); // Some patience
const timeoutId = setTimeout(() => {
PID.signal(pid, 'SIGKILL');
PID.signal(pid, 'SIGKILL');
PID.signal(pid, 'SIGKILL');
}, 3000);
const intervalId = setInterval(async () => {
if (PID.exists(pid))
return;
clearTimeout(timeoutId);
clearInterval(intervalId);
resolve();
}, 50);
});
},
signal: (pid, signal) => {
try {
return process.kill(pid, signal);
}
catch {
return false;
}
},
usage: async (pid) => {
if (!pid)
return;
try {
const { cpu, memory, elapsed: uptime } = await pidusage(pid);
const birthtime = Date.now() - uptime;
return { cpu, memory, birthtime, uptime };
}
catch {
return;
}
}
};
/* EXPORT */
export default PID;