pool_lad v0.0.5 PoolLad

pool_lad is the younger & more energetic version of :poolboy.

It's still the lightweight, generic pooling library with focus on simplicity, performance, and rock-solid disaster recovery that we all love...

...but it has just gotten a much needed facelift!

Sample usage

The APIs are almost identical to those of :poolboy.

Via manual ownership:

iex(1)> {:ok, worker} = PoolLad.borrow(MyWorkerPool)
{:ok, #PID<0.256.0>}
iex(2)> GenServer.call(worker, :get_random_colour)
:blue
iex(3)> PoolLad.return(MyWorkerPool, worker)
:ok

Via transactional ownership:

iex(1)> PoolLad.transaction(
...(1)>   MyWorkerPool,
...(1)>   fn worker -> GenServer.call(worker, :get_random_colour) end
...(1)> )
:green

Link to this section Summary

Functions

Attempts to "borrow" a worker (pid), or waits until one becomes available.

Returns a specification to start this module under a Supervisor.

Returns a specification to start this module under a Supervisor.

Returns the borrowed worker (pid) back to the pool.

Starts a new PoolLad worker pool.

Both the borrow and the return are facilitated via a single transaction.

Link to this section Functions

Link to this function

borrow(pool, wait? \\ true, timeout \\ 5000)

Specs

borrow(module(), boolean(), integer()) ::
  {:ok, pid()} | {:error, reason :: :full | :timeout}

Attempts to "borrow" a worker (pid), or waits until one becomes available.

Examples

Get, or wait

If no workers are currently available waits (blocks) until one becomes available, or until timeout elapses in which case {:error, :timeout} will be returned.

Assuming we only have one worker available:

iex(1)> {:ok, pid} = PoolLad.borrow(MyWorkerPool)
{:ok, #PID<0.229.0>}
iex(2)> result = PoolLad.borrow(MyWorkerPool) # will wait (block) for 5 seconds first
{:error, :timeout}

Synchronous get

If no workers are currently available, returns {:error, :full} immediately.

Assuming we only have one worker available:

iex(1)> {:ok, pid} = PoolLad.borrow(MyWorkerPool, false)
{:ok, #PID<0.229.0>}
iex(2)> result = PoolLad.borrow(MyWorkerPool, false) # will return imediately
{:error, :full}

Custom timeout

You can configure your own timeout like so:

iex(1)> {:ok, pid} = PoolLad.borrow(MyWorkerPool, true, 2_500)
Link to this function

child_spec(init_arg)

Specs

child_spec({keyword(), keyword()}) :: Supervisor.child_spec()

Returns a specification to start this module under a Supervisor.

Usage

pool_opts = [name: MyWorkerPool, worker_count: 3, worker_module: MyWorker]
worker_opts = [initial_colours: ~w(red green blue)a]

children = [
  {PoolLad, {pool_opts, worker_opts}}
]

Supervisor.start_link(children, strategy: :one_for_one)

Calls child_spec/2.

Link to this function

child_spec(pool_opts, worker_opts)

Specs

child_spec(keyword(), keyword()) :: Supervisor.child_spec()

Returns a specification to start this module under a Supervisor.

Usage

pool_opts = [name: MyWorkerPool, worker_count: 3, worker_module: MyWorker]
worker_opts = [initial_colours: ~w(red green blue)a]

children = [
  PoolLad.child_spec(pool_opts, worker_opts)
]

Supervisor.start_link(children, strategy: :one_for_one)
Link to this function

return(pool, pid)

Specs

return(module(), pid()) :: :ok

Returns the borrowed worker (pid) back to the pool.

Examples

iex(1)> {:ok, pid} = PoolLad.borrow(MyWorkerPool)
{:ok, #PID<0.229.0>}
iex(2)> PoolLad.return(MyWorkerPool, pid)
:ok

⚠️ If the worker died while on loan and a return was attempted, the return will be accepted but ignored and a warning will be logged.

⚠️ If the return was attempted more than once, the return will be accepted but ignored and a warning will be logged.

Link to this function

start_link(pool_opts, worker_opts)

Specs

start_link(keyword(), keyword()) :: GenServer.on_start()

Starts a new PoolLad worker pool.

Needs to be supplied pool_opts and worker_opts.

Pool options;

  • :name (required): unique name, used to interact with the pool
  • :worker_count (required): the number of workers to be started and supervised
  • :worker_module (required): the module to be used as a worker, must implement child_spec/1

Worker options; passed as the init_arg when starting worker_module.

Supervision

See child_spec/1, child_spec/2.

Link to this function

transaction(pool, function, timeout \\ 5000)

Specs

transaction(module(), function(), integer()) :: term() | {:error, :timeout}

Both the borrow and the return are facilitated via a single transaction.

Should function raise, a safe return of the worker to the pool is guaranteed.

iex(1)> PoolLad.transaction(
...(1)>   MyWorkerPool,
...(1)>   fn worker -> GenServer.call(worker, :get_random_colour) end
...(1)> )
:green