pool_sup v0.1.0 PoolSup
This module defines a supervisor process that is specialized to manage pool of workers.
- Process defined by this module behaves as a
:simple_one_for_one
supervisor. - Worker processes are spawned using a callback module that implements
PoolSup.Worker
behaviour. - The
PoolSup
process manages which child processes are in use and which are not. - Functions to request pid of a child process that is not in use are also defined.
Example
Suppose we have a module that implements both GenServer
and PoolSup.Worker
behaviours.
iex(1)> defmodule MyWorker do
...(1)> @behaviour PoolSup.Worker
...(1)> use GenServer
...(1)> def start_link(arg) do
...(1)> GenServer.start_link(__MODULE__, arg)
...(1)> end
...(1)> # definitions of gen_server callbacks...
...(1)> end
When we want to have 3 processes that run MyWorker
server:
iex(2)> {:ok, pid} = PoolSup.start_link(MyWorker, {:worker, :arg}, 3, [name: :my_pool])
Each child process is started by MyWorker.start_link({:worker, :arg})
.
Then we can get a pid of a child currently not in use.
iex(3)> child_pid = PoolSup.checkout(:my_pool)
iex(4)> do_something(child_pid)
iex(5)> PoolSup.checkin(:my_pool, child_pid)
Don’t forget to return the child_pid
when finished; for simple use cases PoolSup.transaction/3
comes in handy.
Usage within supervision tree
The following code snippet spawns a supervisor that has PoolSup
process as one of its children.
The PoolSup
process manages 5 worker processes and they will be started by MyWorker.start_link({:worker, :arg})
.
chilldren = [
...
Supervisor.Spec.supervisor(PoolSup, [MyWorker, {:worker, :arg}, 5]),
...
]
Supervisor.start_link(children, [strategy: :one_for_one])
Summary
Functions
Changes capacity (number of worker processes) of a pool
Checks in an in-use worker process and make it available to others
Checks out a worker pid that is currently not used
Checks out a worker pid in a nonblocking manner, i.e. if no available worker found this returns nil
Starts a PoolSup
process linked to the calling process
Query current status of a pool
Temporarily checks out a worker pid, executes the given function using the pid, and checks in the pid
Types
options :: [{:name, GenServer.name}]
pool :: pid | GenServer.name
Functions
Specs
change_capacity(pool, non_neg_integer) :: :ok
Changes capacity (number of worker processes) of a pool.
If new_capacity
is more than the current capacity, new processes are immediately spawned and become available.
Note that, as is the same throughout the OTP framework, spawning processes under supervisor is synchronous operation.
Therefore increasing large number of capacity at once may make a pool unresponsive for a while.
If new_capacity
is less than the current capacity, the pool tries to shutdown workers that are not in use.
Processes currently in use are never interrupted.
If number of in-use workers is more than new_capacity
, reducing further is delayed until any worker process is checked in.
Specs
checkin(pool, pid) :: :ok
Checks in an in-use worker process and make it available to others.
Specs
checkout(pool, timeout) :: nil | pid
Checks out a worker pid that is currently not used.
If no available worker process exists, the caller is blocked until either
- any process becomes available, or
- timeout is reached.
Specs
checkout_nonblock(pool, timeout) :: nil | pid
Checks out a worker pid in a nonblocking manner, i.e. if no available worker found this returns nil
.
Specs
start_link(module, term, non_neg_integer, options) :: GenServer.on_start
Starts a PoolSup
process linked to the calling process.
Arguments
worker_module
is the callback module ofPoolSup.Worker
.worker_init_arg
is the value passed toworker_module.start_link/1
callback function.capacity
is the initial number of workers thisPoolSup
process holds.- Currently only
:name
option is supported for name registration.
Specs
status(pool) :: %{current_capacity: nni, desired_capacity: nni, available: nni, working: nni} when nni: non_neg_integer
Query current status of a pool.
Specs
transaction(pool, (pid -> a), timeout) :: a when a: any
Temporarily checks out a worker pid, executes the given function using the pid, and checks in the pid.
The timeout
parameter is used only in the checkout step; time elapsed during other steps are not counted.