mirror of
https://github.com/Pandipipas/scoreko-electron-dev.git
synced 2026-06-05 21:22:07 +00:00
Investigating Electron Startup Failures
This commit is contained in:
@@ -5,11 +5,10 @@
|
|||||||
1. `src/main/main.ts` loads `appConfig` from `config/runtime-config.ts`.
|
1. `src/main/main.ts` loads `appConfig` from `config/runtime-config.ts`.
|
||||||
2. Installs or refreshes the packaged NodeCG runtime in user data when needed (`nodecg/runtime-provisioner.ts`).
|
2. Installs or refreshes the packaged NodeCG runtime in user data when needed (`nodecg/runtime-provisioner.ts`).
|
||||||
3. Creates windows (`windows/window-factory.ts`).
|
3. Creates windows (`windows/window-factory.ts`).
|
||||||
4. In packaged builds, relaunches once after a fresh runtime install so NodeCG starts from a settled user-data runtime.
|
4. Starts NodeCG with `nodecg/process-manager.ts`.
|
||||||
5. Starts NodeCG with `nodecg/process-manager.ts`.
|
5. Waits for HTTP readiness and shows loading -> main dashboard.
|
||||||
6. Waits for HTTP readiness and shows loading -> main dashboard.
|
6. Checks the configured Gitea latest-release endpoint for optional updates.
|
||||||
7. Checks the configured Gitea latest-release endpoint for optional updates.
|
7. On shutdown, runs a single graceful-stop flow to avoid orphan processes.
|
||||||
8. On shutdown, runs a single graceful-stop flow to avoid orphan processes.
|
|
||||||
|
|
||||||
## Main modules
|
## Main modules
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@
|
|||||||
],
|
],
|
||||||
"icon": "static/icons/icon.ico",
|
"icon": "static/icons/icon.ico",
|
||||||
"executableName": "scoreko",
|
"executableName": "scoreko",
|
||||||
"signAndEditExecutable": false
|
"signAndEditExecutable": true
|
||||||
},
|
},
|
||||||
"nsis": {
|
"nsis": {
|
||||||
"oneClick": false,
|
"oneClick": false,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export type ApplicationControllerConfig = {
|
|||||||
bundleName: string;
|
bundleName: string;
|
||||||
log: (...args: unknown[]) => void;
|
log: (...args: unknown[]) => void;
|
||||||
}) => PreparedNodecgRuntime;
|
}) => PreparedNodecgRuntime;
|
||||||
relaunch: () => void;
|
|
||||||
scheduleUpdateCheck: (config: {
|
scheduleUpdateCheck: (config: {
|
||||||
getParentWindow: () => ApplicationWindow | null;
|
getParentWindow: () => ApplicationWindow | null;
|
||||||
beforeInstall: () => Promise<void>;
|
beforeInstall: () => Promise<void>;
|
||||||
@@ -129,13 +128,6 @@ export function createApplicationController({
|
|||||||
log: deps.log,
|
log: deps.log,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (preparedRuntime.installed && isPackaged) {
|
|
||||||
deps.log("Runtime was installed or refreshed; relaunching Scoreko before starting NodeCG.");
|
|
||||||
deps.relaunch();
|
|
||||||
deps.exit(0);
|
|
||||||
state = "stopped";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodecgManager = deps.createNodecgProcessManager(preparedRuntime.runtimePath);
|
nodecgManager = deps.createNodecgProcessManager(preparedRuntime.runtimePath);
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ export function bootstrap(): void {
|
|||||||
getAllWindows: () => BrowserWindow.getAllWindows(),
|
getAllWindows: () => BrowserWindow.getAllWindows(),
|
||||||
log,
|
log,
|
||||||
prepareRuntime: prepareUserNodecgRuntime,
|
prepareRuntime: prepareUserNodecgRuntime,
|
||||||
relaunch: () => app.relaunch(),
|
|
||||||
scheduleUpdateCheck: ({ getParentWindow, beforeInstall }) => {
|
scheduleUpdateCheck: ({ getParentWindow, beforeInstall }) => {
|
||||||
scheduleUpdateCheck({
|
scheduleUpdateCheck({
|
||||||
appConfig,
|
appConfig,
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ test("ApplicationController preserves startup ordering and schedules updates aft
|
|||||||
events.push("prepare-runtime");
|
events.push("prepare-runtime");
|
||||||
return { runtimePath: "/user-data/scoreko/nodecg", installed: false };
|
return { runtimePath: "/user-data/scoreko/nodecg", installed: false };
|
||||||
},
|
},
|
||||||
relaunch: () => events.push("relaunch"),
|
|
||||||
scheduleUpdateCheck: () => events.push("schedule-update"),
|
scheduleUpdateCheck: () => events.push("schedule-update"),
|
||||||
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
||||||
exit: (code) => events.push(`exit:${code}`),
|
exit: (code) => events.push(`exit:${code}`),
|
||||||
@@ -145,7 +144,7 @@ test("ApplicationController preserves startup ordering and schedules updates aft
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ApplicationController relaunches packaged app after runtime install before starting NodeCG", async () => {
|
test("ApplicationController directly launches packaged app after runtime install without relaunching", async () => {
|
||||||
const events: string[] = [];
|
const events: string[] = [];
|
||||||
const controller = createApplicationController({
|
const controller = createApplicationController({
|
||||||
appConfig: getBaseConfig(),
|
appConfig: getBaseConfig(),
|
||||||
@@ -162,31 +161,45 @@ test("ApplicationController relaunches packaged app after runtime install before
|
|||||||
},
|
},
|
||||||
deps: {
|
deps: {
|
||||||
createLoadingWindow: () => {
|
createLoadingWindow: () => {
|
||||||
throw new Error("window creation should wait until after relaunch decisions");
|
events.push("create-loading");
|
||||||
|
return new MockWindow("loading", events);
|
||||||
},
|
},
|
||||||
createMainWindow: () => {
|
createMainWindow: () => {
|
||||||
throw new Error("window creation should wait until after relaunch decisions");
|
events.push("create-main");
|
||||||
|
return new MockWindow("main", events);
|
||||||
},
|
},
|
||||||
createNodecgProcessManager: () => {
|
createNodecgProcessManager: () => {
|
||||||
throw new Error("NodeCG should not start before relaunch");
|
events.push("create-manager");
|
||||||
|
return createMockManager(events);
|
||||||
},
|
},
|
||||||
getAllWindows: () => [],
|
getAllWindows: () => [],
|
||||||
log: (...args) => events.push(String(args[0])),
|
log: (...args) => events.push(String(args[0])),
|
||||||
prepareRuntime: () => ({ runtimePath: "/user-data/scoreko/nodecg", installed: true }),
|
prepareRuntime: () => ({ runtimePath: "/user-data/scoreko/nodecg", installed: true }),
|
||||||
relaunch: () => events.push("relaunch"),
|
|
||||||
scheduleUpdateCheck: () => events.push("schedule-update"),
|
scheduleUpdateCheck: () => events.push("schedule-update"),
|
||||||
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
||||||
exit: (code) => events.push(`exit:${code}`),
|
exit: (code) => events.push(`exit:${code}`),
|
||||||
|
now: () => 0,
|
||||||
|
sleep: async (ms) => {
|
||||||
|
events.push(`sleep:${ms}`);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await controller.launch();
|
await controller.launch();
|
||||||
|
|
||||||
assert.equal(controller.getState(), "stopped");
|
assert.equal(controller.getState(), "ready");
|
||||||
assert.deepEqual(events, [
|
assert.deepEqual(events, [
|
||||||
"Runtime was installed or refreshed; relaunching Scoreko before starting NodeCG.",
|
"create-manager",
|
||||||
"relaunch",
|
"create-main",
|
||||||
"exit:0",
|
"create-loading",
|
||||||
|
"start-nodecg",
|
||||||
|
"wait-nodecg",
|
||||||
|
"loading:load:http://localhost:9090/loading",
|
||||||
|
"loading:show",
|
||||||
|
"main:load:http://localhost:9090/main",
|
||||||
|
"main:show",
|
||||||
|
"loading:close",
|
||||||
|
"schedule-update",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -215,7 +228,6 @@ test("ApplicationController activation before readiness routes through launch",
|
|||||||
events.push("prepare-runtime");
|
events.push("prepare-runtime");
|
||||||
return { runtimePath: "/user-data/scoreko/nodecg", installed: false };
|
return { runtimePath: "/user-data/scoreko/nodecg", installed: false };
|
||||||
},
|
},
|
||||||
relaunch: () => events.push("relaunch"),
|
|
||||||
scheduleUpdateCheck: () => events.push("schedule-update"),
|
scheduleUpdateCheck: () => events.push("schedule-update"),
|
||||||
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
||||||
exit: (code) => events.push(`exit:${code}`),
|
exit: (code) => events.push(`exit:${code}`),
|
||||||
@@ -253,7 +265,6 @@ test("ApplicationController shutdown is idempotent", async () => {
|
|||||||
getAllWindows: () => [],
|
getAllWindows: () => [],
|
||||||
log: () => undefined,
|
log: () => undefined,
|
||||||
prepareRuntime: () => ({ runtimePath: "/user-data/scoreko/nodecg", installed: false }),
|
prepareRuntime: () => ({ runtimePath: "/user-data/scoreko/nodecg", installed: false }),
|
||||||
relaunch: () => events.push("relaunch"),
|
|
||||||
scheduleUpdateCheck: () => events.push("schedule-update"),
|
scheduleUpdateCheck: () => events.push("schedule-update"),
|
||||||
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
setAppUserModelId: () => events.push("set-app-user-model-id"),
|
||||||
exit: (code) => events.push(`exit:${code}`),
|
exit: (code) => events.push(`exit:${code}`),
|
||||||
|
|||||||
Reference in New Issue
Block a user