fix(electron): improve child process termination handling during app quit to ensure graceful shutdown

This commit is contained in:
Ivan committed 2026-04-13 23:35:23 -05:00
1 parent e266279538
commit 2e759108c1
4 files changed
+90 -29

No files matched your search

+37 -11
View File
@@ -500,21 +500,47 @@ app.whenReady().then(async () => {
});
function quit() {
// kill python process
if (exeChildProcess) {
exeChildProcess.kill("SIGKILL");
if (!exeChildProcess) {
app.quit();
return;
}
// quit electron app
app.quit();
if (exeChildProcess.exitCode !== null || exeChildProcess.signalCode !== null) {
return;
}
try {
exeChildProcess.kill("SIGTERM");
} catch (e) {
log(e);
try {
exeChildProcess.kill("SIGKILL");
} catch (e2) {
log(e2);
}
app.quit();
return;
}
const timeoutMs = 5000;
const timeout = setTimeout(() => {
try {
if (
exeChildProcess &&
exeChildProcess.exitCode === null &&
exeChildProcess.signalCode === null
) {
exeChildProcess.kill("SIGKILL");
}
} catch (e) {
log(e);
}
app.quit();
}, timeoutMs);
exeChildProcess.once("exit", () => {
clearTimeout(timeout);
app.quit();
});
}
// quit electron if all windows are closed
app.on("window-all-closed", () => {
quit();
});
// make sure child process is killed if app is quiting
app.on("quit", () => {
quit();
});
+37 -11
View File
@@ -752,21 +752,47 @@ app.whenReady().then(async () => {
});
function quit() {
// kill python process
if (exeChildProcess) {
exeChildProcess.kill("SIGKILL");
if (!exeChildProcess) {
app.quit();
return;
}
// quit electron app
app.quit();
if (exeChildProcess.exitCode !== null || exeChildProcess.signalCode !== null) {
return;
}
try {
exeChildProcess.kill("SIGTERM");
} catch (e) {
log(e);
try {
exeChildProcess.kill("SIGKILL");
} catch (e2) {
log(e2);
}
app.quit();
return;
}
const timeoutMs = 5000;
const timeout = setTimeout(() => {
try {
if (
exeChildProcess &&
exeChildProcess.exitCode === null &&
exeChildProcess.signalCode === null
) {
exeChildProcess.kill("SIGKILL");
}
} catch (e) {
log(e);
}
app.quit();
}, timeoutMs);
exeChildProcess.once("exit", () => {
clearTimeout(timeout);
app.quit();
});
}
// quit electron if all windows are closed
app.on("window-all-closed", () => {
quit();
});
// make sure child process is killed if app is quiting
app.on("quit", () => {
quit();
});
+9
View File
@@ -2296,6 +2296,15 @@ class ReticulumMeshChat:
# web server has shutdown, likely ctrl+c, but if we don't do the following, the script never exits
async def shutdown(self, app):
for identity_hash in list(self.contexts.keys()):
ctx = self.contexts.get(identity_hash)
if ctx is None:
continue
bh = getattr(ctx, "bot_handler", None)
if bh is not None:
with contextlib.suppress(Exception):
bh.stop_all()
if hasattr(self, "page_node_manager"):
self.page_node_manager.teardown()
+7 -7
View File
@@ -475,6 +475,13 @@ class IdentityContext:
self.auto_propagation_manager.stop()
self.auto_propagation_manager = None
if self.bot_handler:
try:
self.bot_handler.stop_all()
except Exception as e:
print(f"Error while stopping bots for {self.identity_hash}: {e}")
self.bot_handler = None
# 1. Deregister announce handlers
for handler in self.announce_handlers:
with contextlib.suppress(Exception):
@@ -586,13 +593,6 @@ class IdentityContext:
if self.nomadnet_manager:
self.nomadnet_manager = None
if self.bot_handler:
try:
self.bot_handler.stop_all()
except Exception as e:
print(f"Error while stopping bots for {self.identity_hash}: {e}")
self.bot_handler = None
if self.database:
try:
if not getattr(self.app, "emergency", False):