Tuning

Concurrency is the pool size

The render pipeline’s concurrency is bound to the browser pool: the number of render workers equals --render-pool-max-total. The default is 1 — a single browser, serial rendering. For any real load, raise it:

-e RENDER_POOL_MAX_TOTAL=4
-e RENDER_POOL_MIN_IDLE=1
-e RENDER_POOL_MAX_IDLE=4

Each browser consumes memory and CPU; size MAX_TOTAL to your container’s resources and expected concurrency, and set container memory/CPU limits.

Timeouts

SettingDefaultPurpose
--render-timeout30sMax time for one render.
--render-retry-attempts3Retries on failure. A slow render can consume up to timeout × attempts.
--render-pool-borrow-timeout1mMax wait to acquire a browser when the pool is saturated.
--render-pool-repay-timeout5sMax time to return/clean up a browser.

With the default single-browser pool and these timeouts, one slow render serializes everything behind it. Raising the pool size and bounding per-request time at your proxy both help.

Recycling

Browsers are recycled by two mechanisms:

  • Usage count — a browser/tab is destroyed after --factory-max-usage-count renders (default 1000), bounding memory growth.
  • Eviction — idle browsers are periodically evicted (--render-pool-time-between-eviction, default 1h).

Health checks

/_status borrows a browser to read live version info, so under a saturated single-browser pool it can block up to the borrow timeout. Use /_metadata for liveness (it does not touch the pool), and either size the pool with headroom or treat /_status as a readiness check with a generous timeout.

page vs runner

For high throughput on Chromium, --factory-type=page reuses one browser process across tabs, reducing per-render startup cost. runner gives stronger isolation (a crash affects only one render). Benchmark both for your workload.