one switch for sidecar timeouts

SIDECAR_TIMEOUTS=1 puts the old behaviour back — Bun's built-in fetch
ceiling outbound, and the inbound drop at whatever each plugin declared.
unset, which is the default, means no ceiling on either leg.

one constant in one file rather than a knob per plugin: turning it on or
off should not mean remembering which of eight routers to edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-24 17:55:07 +00:00
co-authored by Claude Opus 5
parent a321babb28
commit fdd53b0dd9
2 changed files with 28 additions and 5 deletions
+5
View File
@@ -85,3 +85,8 @@ PUBLIC_URL=http://localhost:9000
# Immich (officer-photos) is configured from the app, not from here — Photos → Connection. Instances and
# their API keys live encrypted in `photos_config`, so the platform never sees a key.
# Put request timeouts back on sidecar proxies. Unset is the default and means NO timeout on either leg:
# long requests arrive from everywhere (transcribing a 42-minute recording, a from-scratch music reindex)
# and every ceiling is a number somebody guessed. Set to 1 only to restore the old behaviour.
# SIDECAR_TIMEOUTS=1
+20 -2
View File
@@ -94,6 +94,19 @@ export type SidecarProxy = {
getWsUrl: () => string | null;
};
/**
* The one switch for sidecar request timeouts.
*
* Off by default: no ceiling on either leg, because long requests arrive from everywhere and every
* ceiling is a number somebody guessed. Set `SIDECAR_TIMEOUTS=1` in `.env` and restart to put the old
* behaviour back — Bun's built-in fetch ceiling outbound, and the inbound drop at whatever each plugin
* declared (or the server's 60s default if it declared nothing).
*
* Here rather than per plugin so turning it on or off is one line in one file, and so nobody has to
* remember which of eight routers to edit.
*/
const TIMEOUTS_ON = process.env.SIDECAR_TIMEOUTS === '1';
export function createSidecarProxy({
name,
prefix,
@@ -142,11 +155,16 @@ export function createSidecarProxy({
the 60s default drop.
*/
const server = ctx.env as { timeout?: (req: Request, seconds: number) => void } | undefined;
// `0` disables the idle timeout. With the switch on, an undeclared plugin falls back to the server's
// own 60s default by not being touched at all.
const inbound = TIMEOUTS_ON ? timeoutSeconds : (timeoutSeconds ?? 0);
if (inbound !== undefined) {
try {
server?.timeout?.(ctx.req.raw, timeoutSeconds ?? 0);
server?.timeout?.(ctx.req.raw, inbound);
} catch {
/* no per-request timeout available */
}
}
const method = ctx.req.method;
const headers: Record<string, string> = {};
@@ -228,7 +246,7 @@ export function createSidecarProxy({
headers,
body,
duplex: 'half',
timeout: false,
...(TIMEOUTS_ON ? {} : { timeout: false }),
};
let upstream: Response;