Keep daemon logs after a button restart
This commit is contained in:
@@ -40,6 +40,9 @@ mobile draft at 390px.
|
|||||||
- [x] C11 preview caching: Discord-hosted image/GIF previews (WebP 320px, hash-addressed, 5 MiB
|
- [x] C11 preview caching: Discord-hosted image/GIF previews (WebP 320px, hash-addressed, 5 MiB
|
||||||
cap, one attempt) run after every walk in both modes. Live run `...-20260916090722`:
|
cap, one attempt) run after every walk in both modes. Live run `...-20260916090722`:
|
||||||
`previewed: 2`; thumbs served over `/api/media/<scrape>/<item>/thumb` (200).
|
`previewed: 2`; thumbs served over `/api/media/<scrape>/<item>/thumb` (200).
|
||||||
|
- [x] C41 Restart keeps its logs. A button restart spawned the replacement with `stdio: ignore`,
|
||||||
|
so anything after the restart vanished. The replacement now appends to `daemon.log` beside the
|
||||||
|
token file (`VESKSLOP_DAEMON_LOG` overrides); documented in [docs/daemon.md](docs/daemon.md).
|
||||||
- [x] C40 Stale scrape states. Two `general_chut` scrapes showed `running` because the daemons
|
- [x] C40 Stale scrape states. Two `general_chut` scrapes showed `running` because the daemons
|
||||||
that owned them were killed mid-job; the state file kept the last written value. On daemon
|
that owned them were killed mid-job; the state file kept the last written value. On daemon
|
||||||
start the engine now reconciles `running`/`queued` scrapes to `paused`, and History has a
|
start the engine now reconciles `running`/`queued` scrapes to `paused`, and History has a
|
||||||
|
|||||||
@@ -145,6 +145,14 @@ Core tab and the `/api/core/*` routes use it.
|
|||||||
Verified live on 2026-09-13: the web UI started the client under auto-Xvfb, the bridge connected,
|
Verified live on 2026-09-13: the web UI started the client under auto-Xvfb, the bridge connected,
|
||||||
`state.get` returned the real account and guilds, and stop exited with code 0.
|
`state.get` returned the real account and guilds, and stop exited with code 0.
|
||||||
|
|
||||||
|
## Self-restart
|
||||||
|
|
||||||
|
`POST /api/daemon/restart` (Settings → Server → **Restart daemon**) replaces the daemon process
|
||||||
|
without touching the client. The replacement detaches, so the terminal or parent shell can close.
|
||||||
|
It appends stdout and stderr to `daemon.log` next to the token file (`poc/daemon.log` by default;
|
||||||
|
`VESKSLOP_DAEMON_LOG` overrides). On start it pauses scrapes still marked `running` by a previous
|
||||||
|
daemon, so a hard kill never leaves ghost jobs.
|
||||||
|
|
||||||
## Health endpoint
|
## Health endpoint
|
||||||
|
|
||||||
`GET /health` returns the core connection state, the socket path, the owner ID, and the query count.
|
`GET /health` returns the core connection state, the socket path, the owner ID, and the query count.
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
|
import { closeSync, openSync } from "node:fs";
|
||||||
import { config as loadEnv } from "dotenv";
|
import { config as loadEnv } from "dotenv";
|
||||||
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
@@ -1051,14 +1052,18 @@ function restartDaemon(): void {
|
|||||||
const args = [...process.execArgv, ...process.argv.slice(1)];
|
const args = [...process.execArgv, ...process.argv.slice(1)];
|
||||||
const command = `${quote(process.execPath)} ${args.map(quote).join(" ")}`;
|
const command = `${quote(process.execPath)} ${args.map(quote).join(" ")}`;
|
||||||
|
|
||||||
console.log("[daemon] restart requested: spawning a replacement");
|
const logPath = process.env.VESKSLOP_DAEMON_LOG ?? join(dirname(tokenFile), "daemon.log");
|
||||||
|
console.log(`[daemon] restart requested: spawning a replacement, appending to ${logPath}`);
|
||||||
|
|
||||||
|
const logFd = openSync(logPath, "a");
|
||||||
const child = spawn("sh", ["-c", `sleep 2; exec ${command}`], {
|
const child = spawn("sh", ["-c", `sleep 2; exec ${command}`], {
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: "ignore",
|
stdio: ["ignore", logFd, logFd],
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
env: { ...process.env, VESKSLOP_DAEMON_RESTART: "1" }
|
env: { ...process.env, VESKSLOP_DAEMON_RESTART: "1" }
|
||||||
});
|
});
|
||||||
child.unref();
|
child.unref();
|
||||||
|
closeSync(logFd);
|
||||||
|
|
||||||
setTimeout(() => shutdown(true), 300);
|
setTimeout(() => shutdown(true), 300);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user