From de0642766cdfb88cc4a3fcbdb0b60bb62a13e99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 27 Jul 2026 15:23:27 +0000 Subject: [PATCH] music: 30-min per-request idle timeout for reindex/manifest (from-scratch builds) A from-scratch rebuild holds the triggering request open for many minutes with no bytes flowing, so both server hops' idle timeouts would drop it. Bun caps the server-level idleTimeout at 255s, but server.timeout(req, seconds) allows more per-request: - sidecar Bun.serve: extend /reindex, /manifest, /reindex/stream to 1800s. - platform proxy (music router): same, via the Bun server exposed as Hono's env. Baseline idleTimeouts unchanged (sidecar 255, main server 60). The build always completed in the background regardless; this keeps the request itself alive. Co-Authored-By: Claude Opus 4.8 --- src/servers/api/music/router.ts | 12 ++++++++++++ src/servers/sidecar/music/index.ts | 12 ++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/servers/api/music/router.ts b/src/servers/api/music/router.ts index c8ddf916..78d1f356 100644 --- a/src/servers/api/music/router.ts +++ b/src/servers/api/music/router.ts @@ -90,6 +90,18 @@ musicRouter.all('/*', async (ctx) => { const subpath = url.pathname.slice(PREFIX.length) || '/'; const target = `${baseUrl}${subpath}${url.search}`; + // A from-scratch reindex holds this proxied connection open for minutes with no bytes flowing, which + // the main server's 60s idle timeout would drop. Extend it to 30 min for the build/progress endpoints + // (Bun passes the server as Hono's env). Matches the sidecar's own per-request extension. + if (subpath === '/reindex' || subpath === '/manifest' || subpath === '/reindex/stream') { + const server = ctx.env as { timeout?: (req: Request, seconds: number) => void } | undefined; + try { + server?.timeout?.(ctx.req.raw, 1800); + } catch { + /* older Bun / no per-request timeout — the build still completes in the background */ + } + } + const range = ctx.req.header('range'); let upstream: Response; try { diff --git a/src/servers/sidecar/music/index.ts b/src/servers/sidecar/music/index.ts index 1f5a73df..5f720853 100644 --- a/src/servers/sidecar/music/index.ts +++ b/src/servers/sidecar/music/index.ts @@ -74,12 +74,16 @@ const port = getFreePort(); const server = Bun.serve({ port, hostname: '127.0.0.1', - // A blocking /reindex (esp. the one-time full rebuild) and long range/SSE reads far outlast Bun's - // default 10s request idle-timeout, which would drop them mid-flight. 255s is Bun's max; a build that - // still outruns it completes in the background anyway (the promise isn't cancelled by a closed socket). + // Bun caps the server-level idleTimeout at 255s. Keep it there as the baseline; the build/stream + // endpoints (which can idle for a whole from-scratch rebuild) extend it per-request via server.timeout. idleTimeout: 255, - async fetch(req) { + async fetch(req, server) { const url = new URL(req.url); + // A from-scratch reindex can take many minutes with no bytes flowing on the triggering request. + // Give the build-triggering + progress endpoints a 30-min idle timeout so they aren't dropped. + if (url.pathname === '/reindex' || url.pathname === '/manifest' || url.pathname === '/reindex/stream') { + server.timeout(req, 1800); + } const json = (data: unknown, init?: ResponseInit) => new Response(JSON.stringify(data), { ...init, headers: { 'Content-Type': 'application/json', ...init?.headers } });