Files
mangaBookmark/docs/adr/0005-on-demand-browser.md
T

49 lines
2.4 KiB
Markdown

# ADR-0005: On-demand browser sidecar
Date: 2026-08-09
Status: accepted
## Decision
Keep the `headless-shell` service and its CDP port alive, but start Google Chrome
only when the first CDP connection arrives. The entrypoint supervises a `socat`
front-end, serializes browser start/reap state with `flock`, and tracks each
connection with a marker named for its helper PID. A reaper stops Chrome after
300 seconds with no live markers. Marker reconciliation covers a helper killed
before its cleanup trap runs.
Chrome runs in its own process group so reap sends the termination signal to
Chrome and its renderer children. The explicit `/home/chrome/profile` user-data
directory remains: Chrome remaps remote debugging to loopback on modern builds,
and Chrome ignores remote-debugging flags on a default profile. `socat` therefore
continues to front Chrome's loopback CDP port.
The profile is a named Compose volume. Clearance cookies survive both a reap and
`docker compose up --build`; the browser still starts with a fresh debugger UUID,
so chromedp must keep endpoint discovery enabled and must not use
`chromedp.NoModifyURL`.
The socat front-end and explicit profile are retained because Chromium remaps a
non-loopback debugging address to loopback since M113, while Chrome ignores the
remote-debugging flags on a default profile since Chrome 136. Flag tuning is
deliberately not adopted: its roughly 30% idle-footprint saving is irrelevant
to a browser that exists for seconds per wake and risks an untested fingerprint.
## Constraints
The 300-second floor is deliberate. Chromium batches cookie persistence on a
roughly 31-second timer, and Go's default HTTP transport can keep the discovery
connection parked for about 90 seconds after use. Reaping only with zero live
connections holds Chrome through both windows and through the poller's staggered
batch plus cover prefetch.
The anti-bot properties remain unchanged: a plausible non-UTC timezone, a
Chrome-version-derived User-Agent without `HeadlessChrome`, and no automation
flag. A remote browser restart can surface as `context.Canceled`, the same error
as a caller deadline, so the backend wraps cancellation observed with a closed
CDP connection as `browser interrupted`; the focused test asserts that
classification without killing a real browser.
The same process-group stop runs during supervisor shutdown, not only during
idle reap, so Chrome can flush its cookie batch before a container rebuild or
graceful stop.