pool_sup v0.2.3 PoolSup.Multi
Defines a supervisor that is specialized to manage multiple PoolSup
processes.
For high-throughput use cases, centralized process pool such as PoolSup
may become a bottleneck as all the messages must be handled by the pool manager process.
This module is for these situations: to manage multiple PoolSup
s and
load-balance checkout requests to multiple pool manager processes.
In summary,
- Process defined by
PoolSup.Multi
behaves as a:simple_one_for_one
supervisor. - Children of
PoolSup.Multi
arePoolSup
processes and they have identical configurations (worker module, capacity, etc.). checkout/3
,checkout_nonblocking/3
andtransaction/4
which randomly picks a pool in aPoolSup.Multi
(with the help of ETS) are provided.- Number of pools and capacity of each pool are dynamically configurable.
Example
Suppose we have the following worker module:
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
To use PoolSup.Multi
it’s necessary to setup an ETS table.
iex(2)> table_id = :ets.new(:arbitrary_table_name, [:set, :public, {:read_concurrency, true}])
Note that the PoolSup.Multi
process must be able to write to the table.
The following creates a PoolSup.Multi
process that has 3 PoolSup
s each of which manages 5 reserved and 2 ondemand workers.
iex(3)> {:ok, pool_multi_pid} = PoolSup.Multi.start_link(table_id, "arbitrary_key", 3, MyWorker, {:worker, :arg}, 5, 2)
Now we can checkout a worker pid from the set of pools:
iex(4)> {pool_pid, worker_pid} = PoolSup.Multi.checkout(table_id, "arbitrary_key")
iex(5)> do_something(worker_pid)
iex(6)> PoolSup.checkin(pool_pid, worker_pid)
Summary
Functions
Changes configuration of an existing PoolSup.Multi
process
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 in the randomly chosen pool this returns nil
See PoolSup.CustomSupHelper.format_status/2
Starts a PoolSup.Multi
process linked to the calling process
See PoolSup.CustomSupHelper.terminate/2
Picks a pool from the specified ETS record, checks out a worker pid, executes the given function using the pid, and then checks in the pid
Types
options :: [{:name, GenServer.name}]
pool_multi :: pid | GenServer.name
pool_multi_key :: term
pool_sup_args :: [module | term | non_neg_integer | non_neg_integer]
Functions
Specs
change_configuration(pool_multi, nil_or_nni, nil_or_nni, nil_or_nni) :: :ok when nil_or_nni: nil | non_neg_integer
Changes configuration of an existing PoolSup.Multi
process.
new_n_pools
, new_reserved
and/or new_ondemand
parameters can be nil
; in that case the original value is kept unchanged.
Changing number of pools
- When
new_n_pools
is larger than the current number of working pools,PoolSup.Multi
spawns new pools immediately. When
new_n_pools
is smaller than the current number of working pools,PoolSup.Multi
process- randomly chooses pools to terminate and mark them “not working”,
- exclude those pools from the ETS record,
- resets their
reserved
andondemand
as0
so that new checkouts will never succeed, - starts to periodically poll the status of “not working” pools, and
- terminate a pool when it becomes ready to terminate (i.e. no worker process is used).
Changing reserved
and/or ondemand
of each pool
- The given values of
reserved
,ondemand
are notified to all the working pools. SeePoolSup.change_capacity/3
for the behaviour of each pool.
Specs
checkout(:ets.tab, pool_multi_key, timeout) :: {pid, pid}
Checks out a worker pid that is currently not used.
Internally this function looks-up the specified ETS record, randomly chooses one of the pools and checks-out a worker in the pool.
Note that this function returns a pair of pid
s: {pool_pid, worker_pid}
.
The returned pool_pid
must be used when returning the worker to the pool: PoolSup.checkin(pool_pid, worker_pid)
.
Specs
checkout_nonblocking(:ets.tab, pool_multi_key, timeout) ::
nil |
{pid, pid}
Checks out a worker pid in a nonblocking manner, i.e. if no available worker found in the randomly chosen pool this returns nil
.
Specs
start_link(:ets.tab, pool_multi_key, non_neg_integer, module, term, non_neg_integer, non_neg_integer, options) :: GenServer.on_start
Starts a PoolSup.Multi
process linked to the calling process.
Arguments
table_id
: ID of the ETS table to use.pool_multi_key
: Key to identify the record in the ETS table. Note thatPoolSup.Multi
keeps track of thePoolSup
s within a single ETS record. Thus multiple instances ofPoolSup.Multi
can share the same ETS table (as long as they use unique keys).n_pools
: Number of pools.worker_module
: Callback module ofPoolSup.Worker
.worker_init_arg
: Value passed toworker_module.start_link/1
.reserved
: Number of reserved workers in eachPoolSup
.ondemand
: Number of ondemand workers in eachPoolSup
.options
: Currently only:name
option for name registration is supported.
Specs
transaction(:ets.tab, pool_multi_key, (pid -> a), timeout) :: a when a: term
Picks a pool from the specified ETS record, checks out a worker pid, executes the given function using the pid, and then checks in the pid.
The timeout
parameter is used only in the checkout step; time elapsed during other steps are not counted.