Skip to main content

CDP browser pool

The app/pdfrender/cdp package manages the headless browser fleet.

Pool (pool.go)​

Built on jolestar/go-commons-pool. Borrowing runs a callback with a page provider; on success the object is returned to the pool, on error it is invalidated (destroyed). Key settings: BlockWhenExhausted, TestOnBorrow (dead browsers are validated out on borrow), a custom force-eviction policy, and the evictor. Defaults: pool size 1, borrow timeout 1m, repay timeout 5s.

Stats() exposes active/idle/destroyed/invalidated counts to /_status.

Factory (factory.go) — two modes​

The factory implements the pool's object lifecycle (MakeObject/DestroyObject/ValidateObject/ActivateObject/PassivateObject) by delegating to a page-wrapper factory chosen by --factory-type:

  • runner — each pooled object is a whole browser process. Make builds and runs a runner, connects DevTools, and wraps the page; Destroy always stops the browser.
  • page — one browser process is launched at construction; each pooled object is a new tab. Chromium only.

ValidateObject recycles a page after --factory-max-usage-count renders or if its navigation history can't be read (dead browser). ActivateObject/ PassivateObject toggle lifecycle-event subscriptions and bump the usage count.

Runner & process management (runner.go)​

The runner launches the browser with a hardened headless flag set, in its own process group (Setpgid). It scans stdout for the DevTools listening on … line to discover the debugging URL.

Teardown is the subtle part: because Chromium's helper processes (GPU, renderers, crash handler) are not children of the main process, Stop SIGTERMs the main process, then polls /proc for any live group member and escalates to SIGKILL across the whole group after --browser-process-group-wait-timeout. A cancelled context escalates immediately. The per-instance temp profile dir is then removed. This is what prevents leaked browser processes.

Render (render.go)​

RenderPDF wraps the whole operation in the render timeout, registers the document with the internal server, builds printToPDF args, and borrows a browser with retries. printPDF sets up the event waiter, navigates, waits, and prints.

Extending​

  • New factory mode: add a FactoryType, a page-wrapper factory, and a case in NewFactory.
  • New wait signal beyond lifecycle events: add a branch in initEventWaiter (like the callback path).