From 79d26e4fc85518e1f1922c35a1a6e31b9d930e3c Mon Sep 17 00:00:00 2001 From: gwleuverink Date: Thu, 7 Aug 2025 12:40:11 +0200 Subject: [PATCH 1/6] cleanup stray scheduler processes --- resources/js/electron-plugin/src/index.ts | 18 +++++++++++------- .../js/electron-plugin/src/server/index.ts | 13 ++++++++++++- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/resources/js/electron-plugin/src/index.ts b/resources/js/electron-plugin/src/index.ts index 65757030..f99fff23 100644 --- a/resources/js/electron-plugin/src/index.ts +++ b/resources/js/electron-plugin/src/index.ts @@ -7,6 +7,7 @@ import { retrieveNativePHPConfig, retrievePhpIniSettings, runScheduler, + killScheduler, startAPI, startPhpApp, } from "./server/index.js"; @@ -22,8 +23,8 @@ const { autoUpdater } = electronUpdater; class NativePHP { processes = []; - schedulerInterval = undefined; mainWindow = null; + schedulerInterval = undefined; public bootstrap( app: CrossProcessExports.App, @@ -244,12 +245,13 @@ class NativePHP { } - private stopScheduler() { - if (this.schedulerInterval) { - clearInterval(this.schedulerInterval); - this.schedulerInterval = null; - } - } + private stopScheduler() { + if (this.schedulerInterval) { + clearInterval(this.schedulerInterval); + this.schedulerInterval = null; + } + killScheduler(); + } private startScheduler() { const now = new Date(); @@ -270,6 +272,8 @@ class NativePHP { } private killChildProcesses() { + this.stopScheduler(); + this.processes .filter((p) => p !== undefined) .forEach((process) => { diff --git a/resources/js/electron-plugin/src/server/index.ts b/resources/js/electron-plugin/src/server/index.ts index 4ef933b8..58be7dfd 100644 --- a/resources/js/electron-plugin/src/server/index.ts +++ b/resources/js/electron-plugin/src/server/index.ts @@ -7,6 +7,9 @@ import { } from "./php.js"; import { appendCookie } from "./utils.js"; import state from "./state.js"; +import { ChildProcess } from "child_process"; + +let schedulerProcess: ChildProcess | null = null; export async function startPhpApp() { const result = await serveApp( @@ -23,7 +26,15 @@ export async function startPhpApp() { } export function runScheduler() { - startScheduler(state.randomSecret, state.electronApiPort, state.phpIni); + killScheduler(); + schedulerProcess = startScheduler(state.randomSecret, state.electronApiPort, state.phpIni); +} + +export function killScheduler() { + if (schedulerProcess && !schedulerProcess.killed) { + schedulerProcess.kill(); + schedulerProcess = null; + } } export function startAPI(): Promise { From d83caac77b2cabd455f76452ad8d8a1ecdc62d07 Mon Sep 17 00:00:00 2001 From: gwleuverink Date: Thu, 7 Aug 2025 16:24:06 +0200 Subject: [PATCH 2/6] make sure process exists before killing it --- resources/js/electron-plugin/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/js/electron-plugin/src/index.ts b/resources/js/electron-plugin/src/index.ts index f99fff23..c56322d5 100644 --- a/resources/js/electron-plugin/src/index.ts +++ b/resources/js/electron-plugin/src/index.ts @@ -277,7 +277,10 @@ class NativePHP { this.processes .filter((p) => p !== undefined) .forEach((process) => { + if (!process || !process.pid) return; + try { + process.kill(0); // Test if process exists (throws error if not) // @ts-ignore killSync(process.pid, 'SIGTERM', true); // Kill tree ps.kill(process.pid); // Sometimes does not kill the subprocess of php server From 4c2fef51477e959666235ebe4bf6060bc1438546 Mon Sep 17 00:00:00 2001 From: gwleuverink <17123491+gwleuverink@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:49:36 +0000 Subject: [PATCH 3/6] Build plugin --- resources/js/electron-plugin/dist/index.js | 9 +++++++-- resources/js/electron-plugin/dist/server/index.js | 10 +++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/resources/js/electron-plugin/dist/index.js b/resources/js/electron-plugin/dist/index.js index c8540284..a3e8bdfe 100644 --- a/resources/js/electron-plugin/dist/index.js +++ b/resources/js/electron-plugin/dist/index.js @@ -11,7 +11,7 @@ import { app, session, powerMonitor } from "electron"; import { initialize } from "@electron/remote/main/index.js"; import state from "./server/state.js"; import { electronApp, optimizer } from "@electron-toolkit/utils"; -import { retrieveNativePHPConfig, retrievePhpIniSettings, runScheduler, startAPI, startPhpApp, } from "./server/index.js"; +import { retrieveNativePHPConfig, retrievePhpIniSettings, runScheduler, killScheduler, startAPI, startPhpApp, } from "./server/index.js"; import { notifyLaravel } from "./server/utils.js"; import { resolve } from "path"; import { stopAllProcesses } from "./server/api/childProcess.js"; @@ -22,8 +22,8 @@ const { autoUpdater } = electronUpdater; class NativePHP { constructor() { this.processes = []; - this.schedulerInterval = undefined; this.mainWindow = null; + this.schedulerInterval = undefined; } bootstrap(app, icon, phpBinary, cert) { initialize(); @@ -192,6 +192,7 @@ class NativePHP { clearInterval(this.schedulerInterval); this.schedulerInterval = null; } + killScheduler(); } startScheduler() { const now = new Date(); @@ -206,10 +207,14 @@ class NativePHP { }, delay); } killChildProcesses() { + this.stopScheduler(); this.processes .filter((p) => p !== undefined) .forEach((process) => { + if (!process || !process.pid) + return; try { + process.kill(0); killSync(process.pid, 'SIGTERM', true); ps.kill(process.pid); } diff --git a/resources/js/electron-plugin/dist/server/index.js b/resources/js/electron-plugin/dist/server/index.js index 0373af8d..7a1f943c 100644 --- a/resources/js/electron-plugin/dist/server/index.js +++ b/resources/js/electron-plugin/dist/server/index.js @@ -11,6 +11,7 @@ import startAPIServer from "./api.js"; import { retrieveNativePHPConfig, retrievePhpIniSettings, serveApp, startScheduler, } from "./php.js"; import { appendCookie } from "./utils.js"; import state from "./state.js"; +let schedulerProcess = null; export function startPhpApp() { return __awaiter(this, void 0, void 0, function* () { const result = yield serveApp(state.randomSecret, state.electronApiPort, state.phpIni); @@ -20,7 +21,14 @@ export function startPhpApp() { }); } export function runScheduler() { - startScheduler(state.randomSecret, state.electronApiPort, state.phpIni); + killScheduler(); + schedulerProcess = startScheduler(state.randomSecret, state.electronApiPort, state.phpIni); +} +export function killScheduler() { + if (schedulerProcess && !schedulerProcess.killed) { + schedulerProcess.kill(); + schedulerProcess = null; + } } export function startAPI() { return startAPIServer(state.randomSecret); From 06181d127bd68b589aff0060f7e45bb432039489 Mon Sep 17 00:00:00 2001 From: gwleuverink Date: Thu, 7 Aug 2025 17:52:16 +0200 Subject: [PATCH 4/6] add guard so no exited processes are killed --- resources/js/electron-plugin/src/index.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/resources/js/electron-plugin/src/index.ts b/resources/js/electron-plugin/src/index.ts index c56322d5..877f16b6 100644 --- a/resources/js/electron-plugin/src/index.ts +++ b/resources/js/electron-plugin/src/index.ts @@ -278,15 +278,18 @@ class NativePHP { .filter((p) => p !== undefined) .forEach((process) => { if (!process || !process.pid) return; + if (process.killed && process.exitCode !== null) return; try { - process.kill(0); // Test if process exists (throws error if not) - // @ts-ignore - killSync(process.pid, 'SIGTERM', true); // Kill tree - ps.kill(process.pid); // Sometimes does not kill the subprocess of php server + + // @ts-ignore + killSync(process.pid, 'SIGTERM', true); // Kill tree + ps.kill(process.pid); // Sometimes does not kill the subprocess of php server + } catch (err) { console.error(err); } + }); } } From 177759f53e4527a5d39a7dc20ca499a17cfbd8ac Mon Sep 17 00:00:00 2001 From: gwleuverink Date: Thu, 7 Aug 2025 17:52:55 +0200 Subject: [PATCH 5/6] improve type annotations --- resources/js/electron-plugin/src/index.ts | 10 +++++----- .../js/electron-plugin/src/server/api/childProcess.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/js/electron-plugin/src/index.ts b/resources/js/electron-plugin/src/index.ts index 877f16b6..a1a8ee96 100644 --- a/resources/js/electron-plugin/src/index.ts +++ b/resources/js/electron-plugin/src/index.ts @@ -1,5 +1,6 @@ import CrossProcessExports from "electron"; import { app, session, powerMonitor } from "electron"; +import { ChildProcessWithoutNullStreams } from "child_process"; import { initialize } from "@electron/remote/main/index.js"; import state from "./server/state.js"; import { electronApp, optimizer } from "@electron-toolkit/utils"; @@ -22,7 +23,7 @@ import electronUpdater from 'electron-updater'; const { autoUpdater } = electronUpdater; class NativePHP { - processes = []; + processes: ChildProcessWithoutNullStreams[] = []; mainWindow = null; schedulerInterval = undefined; @@ -281,10 +282,9 @@ class NativePHP { if (process.killed && process.exitCode !== null) return; try { - - // @ts-ignore - killSync(process.pid, 'SIGTERM', true); // Kill tree - ps.kill(process.pid); // Sometimes does not kill the subprocess of php server + // @ts-ignore + killSync(process.pid, 'SIGTERM', true); // Kill tree + ps.kill(process.pid); // Sometimes does not kill the subprocess of php server } catch (err) { console.error(err); diff --git a/resources/js/electron-plugin/src/server/api/childProcess.ts b/resources/js/electron-plugin/src/server/api/childProcess.ts index c7fd6b5f..0d4421cf 100644 --- a/resources/js/electron-plugin/src/server/api/childProcess.ts +++ b/resources/js/electron-plugin/src/server/api/childProcess.ts @@ -1,5 +1,5 @@ import express from 'express'; -import {utilityProcess} from 'electron'; +import {utilityProcess, UtilityProcess} from 'electron'; import state from '../state.js'; import {notifyLaravel} from "../utils.js"; import {getAppPath, getDefaultEnvironmentVariables, getDefaultPhpIniSettings, runningSecureBuild} from "../php.js"; @@ -207,7 +207,7 @@ export function stopAllProcesses() { } } -function getProcess(alias) { +function getProcess(alias: string): UtilityProcess | undefined { return state.processes[alias]?.proc; } From 9192e291f081c37095e19fe242c384446fa5213d Mon Sep 17 00:00:00 2001 From: gwleuverink <17123491+gwleuverink@users.noreply.github.com> Date: Thu, 7 Aug 2025 21:03:51 +0000 Subject: [PATCH 6/6] Build plugin --- resources/js/electron-plugin/dist/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/js/electron-plugin/dist/index.js b/resources/js/electron-plugin/dist/index.js index a3e8bdfe..42d21924 100644 --- a/resources/js/electron-plugin/dist/index.js +++ b/resources/js/electron-plugin/dist/index.js @@ -213,8 +213,9 @@ class NativePHP { .forEach((process) => { if (!process || !process.pid) return; + if (process.killed && process.exitCode !== null) + return; try { - process.kill(0); killSync(process.pid, 'SIGTERM', true); ps.kill(process.pid); }