CDPEx.Pool (CDPEx v0.4.0)

Copy Markdown View Source

A fixed-size pool of reusable CDPEx.Browser processes.

Launching Chrome is expensive — a cold start can take several seconds on a constrained host, with a fresh profile each time. A pool keeps browsers warm and hands them out for reuse, so a per-job fetch no longer pays a launch on every call.

{:ok, pool} = CDPEx.Pool.start_link(size: 2, launch_opts: [headless: true])

CDPEx.Pool.with_page(pool, fn page ->
  {:ok, _} = CDPEx.Page.navigate(page, "https://example.com")
  CDPEx.Page.html(page)
end)

Browsers are launched lazily up to :size and reused thereafter. checkout/2 blocks (up to :checkout_timeout) when every browser is busy. The pool is resilient: a caller that crashes while holding a browser has it returned automatically, and a browser that crashes is dropped and relaunched on demand — so :size self-heals. Put the pool under your supervision tree; its terminate/2 stops every browser, reaping Chrome.

Browser launches are synchronous — a browser is started inside the pool process, so while one is launching (a cold Chrome can take a few seconds) the pool can't serve other checkouts or checkins. A short :checkout_timeout is therefore unreliable while the pool is still growing to :size; once warm, checkouts are immediate.

Options

  • :size — maximum number of browsers (default 1)
  • :launch_opts — options passed to each CDPEx.Browser (see CDPEx.Chrome)
  • :checkout_timeout — ms to wait for a free browser (default 5_000). While the pool is still launching browsers to :size, keep this above your cold Chrome launch time — launches are synchronous (see below)
  • :name — registers the pool process

Summary

Functions

Returns a browser borrowed with checkout/2.

Borrows a browser, blocking up to timeout ms when all are busy.

Starts a pool. See the moduledoc for options.

Stops the pool, stopping every browser (and reaping Chrome).

Runs fun with a checked-out browser, returning it afterwards (even if fun raises). Returns fun's value, or {:error, reason} if no browser was free.

Runs fun with a fresh page on a pooled browser, cleaning up the page and returning the browser afterwards. The pooled counterpart of CDPEx.with_page/3 — it reuses a warm browser instead of launching one per call.

Types

t()

@type t() :: %CDPEx.Pool{
  available: term(),
  busy: term(),
  count: term(),
  launch_opts: term(),
  size: term(),
  start_fun: term(),
  waiting: term()
}

Functions

checkin(pool, browser)

@spec checkin(GenServer.server(), pid()) :: :ok

Returns a browser borrowed with checkout/2.

checkout(pool, timeout \\ 5000)

@spec checkout(GenServer.server(), timeout()) :: {:ok, pid()} | {:error, term()}

Borrows a browser, blocking up to timeout ms when all are busy.

Returns {:ok, browser}, {:error, :timeout}, or {:error, reason} if a browser had to be launched and failed. Always checkin/2 it when done — or use with_browser/3 / with_page/3, which do that for you.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts a pool. See the moduledoc for options.

stop(pool)

@spec stop(GenServer.server()) :: :ok

Stops the pool, stopping every browser (and reaping Chrome).

with_browser(pool, fun, timeout \\ 5000)

@spec with_browser(GenServer.server(), (pid() -> result), timeout()) ::
  result | {:error, term()}
when result: var

Runs fun with a checked-out browser, returning it afterwards (even if fun raises). Returns fun's value, or {:error, reason} if no browser was free.

with_page(pool, fun, opts \\ [])

@spec with_page(GenServer.server(), (CDPEx.Page.t() -> result), keyword()) ::
  result | {:error, term()}
when result: var

Runs fun with a fresh page on a pooled browser, cleaning up the page and returning the browser afterwards. The pooled counterpart of CDPEx.with_page/3 — it reuses a warm browser instead of launching one per call.

opts are forwarded to CDPEx.with_page/3 (e.g. :prevent_alerts); pass :checkout_timeout to bound the wait for a free browser. Returns fun's value, or {:error, reason}.