@mytec: iter2.4.2 start

This commit is contained in:
2026-02-01 12:02:52 +02:00
parent fa7378cf3f
commit 4026233b21
10 changed files with 724 additions and 8 deletions

View File

@@ -276,7 +276,10 @@ function createMainWindow() {
store.set('windowState', bounds);
} catch (_e) {}
isQuitting = true;
// Graceful shutdown is async but we also do sync kill as safety net
gracefulShutdown().catch(() => {});
killBackend();
killAllBackendProcesses();
});
// Load frontend
@@ -360,6 +363,67 @@ function killBackend() {
log(`[KILL] Backend cleanup complete (PID was ${pid})`);
}
/**
* Nuclear option: kill ALL rfcp-server processes by name.
* This catches orphaned workers that PID-based kill misses.
*/
function killAllBackendProcesses() {
log('[KILL] killAllBackendProcesses() — killing by process name...');
if (process.platform === 'win32') {
try {
execSync('taskkill /F /IM rfcp-server.exe /T', {
stdio: 'ignore',
timeout: 5000
});
log('[KILL] taskkill /IM rfcp-server.exe completed');
} catch (_e) {
// Error means no processes found — OK
log('[KILL] No rfcp-server.exe processes found (or already killed)');
}
} else {
try {
execSync('pkill -9 -f rfcp-server', {
stdio: 'ignore',
timeout: 5000
});
log('[KILL] pkill rfcp-server completed');
} catch (_e) {
log('[KILL] No rfcp-server processes found');
}
}
}
/**
* Graceful shutdown: ask backend to clean up, then force kill everything.
*/
async function gracefulShutdown() {
log('[SHUTDOWN] Requesting graceful shutdown...');
// Step 1: Ask backend to clean up workers and exit
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 2000);
await fetch('http://127.0.0.1:8888/api/system/shutdown', {
method: 'POST',
signal: controller.signal
});
clearTimeout(timeout);
log('[SHUTDOWN] Backend acknowledged shutdown');
} catch (_e) {
log('[SHUTDOWN] Backend did not respond — force killing');
}
// Step 2: Wait briefly for graceful exit
await new Promise(r => setTimeout(r, 500));
// Step 3: PID-based kill (catches the main process)
killBackend();
// Step 4: Name-based kill (catches orphaned workers)
killAllBackendProcesses();
}
// ── App lifecycle ──────────────────────────────────────────────────
app.whenReady().then(async () => {
@@ -393,6 +457,7 @@ app.on('window-all-closed', () => {
log('[CLOSE] window-all-closed fired');
isQuitting = true;
killBackend();
killAllBackendProcesses();
if (process.platform !== 'darwin') {
app.quit();
@@ -409,11 +474,13 @@ app.on('before-quit', () => {
log('[CLOSE] before-quit fired');
isQuitting = true;
killBackend();
killAllBackendProcesses();
});
app.on('will-quit', () => {
log('[CLOSE] will-quit fired');
killBackend();
killAllBackendProcesses();
if (backendLogStream) {
try { backendLogStream.end(); } catch (_e) {}
@@ -427,6 +494,7 @@ process.on('exit', () => {
console.log(`[KILL] process.exit handler, backendPid=${backendPid}`);
} catch (_e) { /* log stream may be closed */ }
// PID-based kill
if (backendPid) {
try {
if (process.platform === 'win32') {
@@ -438,6 +506,24 @@ process.on('exit', () => {
// Best effort
}
}
// Name-based kill — catches orphaned workers
killAllBackendProcesses();
});
// Handle SIGINT/SIGTERM (Ctrl+C, system shutdown)
process.on('SIGINT', () => {
try { log('[SIGNAL] SIGINT received'); } catch (_e) {}
killBackend();
killAllBackendProcesses();
process.exit(0);
});
process.on('SIGTERM', () => {
try { log('[SIGNAL] SIGTERM received'); } catch (_e) {}
killBackend();
killAllBackendProcesses();
process.exit(0);
});
// ── IPC Handlers ───────────────────────────────────────────────────