-
Notifications
You must be signed in to change notification settings - Fork 906
fix(desktop): don't nuke host services on app update #3620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -55,6 +55,18 @@ const HEALTH_POLL_INTERVAL = 200; | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| const HEALTH_POLL_TIMEOUT = 10_000; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ADOPTED_LIVENESS_INTERVAL = 5_000; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function openLogFile(organizationId: string): number { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dir = manifestDir(organizationId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(dir)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return fs.openSync(path.join(dir, "host-service.log"), "a", 0o600); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Empty Prompt for AI agents
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return -1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+58
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Consider emitting at least a
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: apps/desktop/src/main/lib/host-service-coordinator.ts
Line: 58-68
Comment:
**Silent log-open failure drops all child output**
When `openLogFile` fails (e.g., permissions error, unexpected filesystem issue), it returns `-1` with no warning. The spawn call then falls back to `stdio: "ignore"`, silently discarding all stdout/stderr from the host-service child. Operators will have no indication that logs are missing.
Consider emitting at least a `console.warn` when the file cannot be opened:
```suggestion
function openLogFile(organizationId: string): number {
try {
const dir = manifestDir(organizationId);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
}
return fs.openSync(path.join(dir, "host-service.log"), "a", 0o600);
} catch (err) {
console.warn(
`[host-service:${organizationId}] Failed to open log file, child output will be discarded:`,
err,
);
return -1;
}
}
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function findFreePort(): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new Promise((resolve, reject) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const server = createServer(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -402,10 +414,25 @@ export class HostServiceCoordinator extends EventEmitter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.emitStatus(organizationId, "starting", null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const env = await this.buildEnv(organizationId, port, secret, config); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const child = childProcess.spawn(process.execPath, [this.scriptPath], { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stdio: ["ignore", "pipe", "pipe"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Detached + file-backed stdio so the child outlives the parent's process | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // group (Squirrel.Mac SIGTERMs it during updates) and doesn't depend on | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // parent-held stdout/stderr pipes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const logFd = openLogFile(organizationId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let child: childProcess.ChildProcess; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| child = childProcess.spawn(process.execPath, [this.scriptPath], { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| detached: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stdio: logFd >= 0 ? ["ignore", logFd, logFd] : "ignore", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (logFd >= 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.closeSync(logFd); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const childPid = child.pid; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!childPid) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -415,14 +442,6 @@ export class HostServiceCoordinator extends EventEmitter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| instance.pid = childPid; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| child.stdout?.on("data", (data: Buffer) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[host-service:${organizationId}] ${data.toString().trim()}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| child.stderr?.on("data", (data: Buffer) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `[host-service:${organizationId}] ${data.toString().trim()}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| child.on("exit", (code) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[host-service:${organizationId}] exited with code ${code}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const current = this.instances.get(organizationId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
host-service.logis opened in append mode ("a") with no size cap or rotation. Over time — especially if the host-service restarts frequently or is verbose — this file will grow without bound.Consider either:
.log.1when it exceeds a few MBs), or"w"instead of"a"(acceptable since each spawn is a fresh process whose history can be considered independent).Prompt To Fix With AI