Make browser sidecar on-demand (#44)
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user