View Source PoolSup.Multi (pool_sup v0.6.2)
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 tasks must checkout from a single 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
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)
Link to this section Summary
Functions
Changes :checkout_max_duration
option of child pools.
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
.
Returns a child specification to be used when it's not fully specified by the parent supervisor.
Callback implementation for GenServer.format_status/2
.
Callback implementation for GenServer.init/1
.
Starts a PoolSup.Multi
process linked to the calling process.
Picks a pool from the specified ETS record, checks out a worker pid, creates a link to the worker, executes the given function using the pid, and finally checks-in and unlink.
Link to this section Types
@type option() :: {:name, GenServer.name()} | {:checkout_max_duration, pos_integer()}
@type pool_multi() :: pid() | GenServer.name()
@type pool_multi_key() :: term()
@type pool_sup_args() :: [module() | term() | non_neg_integer() | non_neg_integer()]
Link to this section Functions
@spec change_checkout_max_duration(pool_multi(), nil | pos_integer()) :: :ok
Changes :checkout_max_duration
option of child pools.
See PoolSup.start_link/5
for detailed explanation of :checkout_max_duration
option.
The change will be broadcasted to all existing pools.
Also all pools that start afterward will use the new value of :checkout_max_duration
.
change_configuration(pid_or_name, new_n_pools, new_reserved, new_ondemand)
View Source@spec 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
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
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.
@spec 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)
.
@spec 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
.
@spec child_spec(list()) :: Supervisor.child_spec()
Returns a child specification to be used when it's not fully specified by the parent supervisor.
Callback implementation for GenServer.format_status/2
.
Callback implementation for GenServer.init/1
.
start_link(table_id, pool_multi_key, n_pools, worker_module, worker_init_arg, reserved, ondemand, options \\ [])
View Source@spec start_link( :ets.tab(), pool_multi_key(), non_neg_integer(), module(), term(), non_neg_integer(), non_neg_integer(), [option()] ) :: GenServer.on_start()
Starts a PoolSup.Multi
process linked to the calling process.
arguments
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
: Keyword list of the following options::name
: Used for name registration ofPoolSup.Multi
process.:checkout_max_duration
: An option passed to child pools. SeePoolSup.start_link/5
for detail.
@spec 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, creates a link to the worker, executes the given function using the pid, and finally checks-in and unlink.
The timeout
parameter is used only in the checkout step; time elapsed during other steps are not counted.