Skip to content

Commit

Permalink
Add process termination handling
Browse files Browse the repository at this point in the history
  • Loading branch information
truemiller committed Feb 27, 2024
1 parent 9ad3d3c commit 5a52f0d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 18 deletions.
48 changes: 30 additions & 18 deletions electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const {
OperateCmd,
OperateDirectory,
} = require('./install');
const { killProcessAndChildren } = require('./processes');

// Attempt to acquire the single instance lock
const singleInstanceLock = app.requestSingleInstanceLock();
Expand Down Expand Up @@ -53,30 +54,22 @@ let tray,
operateDaemonPid,
nextAppProcess,
nextAppProcessPid;
let beforeQuitOnceCheck = false;

async function beforeQuit() {
if (beforeQuitOnceCheck) return;
beforeQuitOnceCheck = true;

await new Promise(function (resolve, reject) {
if (operateDaemonPid) {
try {
process.kill(operateDaemonPid, 'SIGKILL');
resolve(true);
} catch (error) {
resolve(false);
await killProcessAndChildren(operateDaemonPid);
} catch (e) {
console.error(e);
}
});
}

if (nextAppProcessPid) {
await new Promise(function (resolve, reject) {
try {
process.kill(nextAppProcessPid, 'SIGKILL');
resolve(true);
} catch (error) {
resolve(false);
}
});
try {
await killProcessAndChildren(nextAppProcessPid);
} catch (e) {
console.error(e);
}
}

tray && tray.destroy();
Expand Down Expand Up @@ -322,3 +315,22 @@ app.on('window-all-closed', () => {
app.on('before-quit', () => {
beforeQuit();
});

// PROCESS SPECIFIC EVENTS (HANDLES NON-GRACEFUL TERMINATION)

process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
// Clean up your child processes here
beforeQuit().then(() => {
process.exit(1); // Exit with a failure code
});
});

['SIGINT', 'SIGTERM'].forEach((signal) => {
process.on(signal, () => {
console.log(`Received ${signal}. Cleaning up...`);
beforeQuit().then(() => {
process.exit(0);
});
});
});
36 changes: 36 additions & 0 deletions electron/processes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const psTree = require('ps-tree');
const { exec } = require('child_process');

const unixKillCommand = 'kill -9';
const windowsKillCommand = 'taskkill /F /PID';

function killProcessAndChildren(pid, isWindows = false) {
return new Promise((resolve, reject) => {
psTree(pid, (err, children) => {
if (err) {
reject(err);
return;
}

// Array of PIDs to kill, starting with the children
const pidsToKill = children.map((p) => p.PID);
pidsToKill.push(pid); // Also kill the main process

const killCommand = isWindows ? windowsKillCommand : unixKillCommand;
const joinedCommand = pidsToKill
.map((pid) => `${killCommand} ${pid}`)
.join('; '); // Separate commands with a semicolon, so they run in sequence even if one fails. Also works on Windows.

exec(joinedCommand, (err) => {
if (err?.message?.includes('No such process')) {
return; // Ignore errors for processes that are already dead
}
reject(err);
});

resolve();
});
});
}

module.exports = { killProcessAndChildren };

0 comments on commit 5a52f0d

Please sign in to comment.