This module defines the sregulator behaviour.
Required callback functions: init/1.
This module provides a job regulator for controlling the level of concurrency
of processes carrying out a task. A process requests permission to run and is
queued until it is allowed to begin. Once the task is complete the process
informs the regulator that is is done. Alternatively the process can ask if
it can continue running and gains priority over any queued processes. The
queue is managed using an sbroker_queue
callback module, and the level
of concurrency by an sregulator_valve
callback module. The message queue
delay and processing delay are monitorred by an sbroker_meter
.
The main function to ask to begin is ask/1
, which blocks until the request
is accepted or the queue drops the request. done/3
is then called after the
task has finished or continue/2
to continue.
A regulator requires a callback module to be configured, in a similar way to
a supervisor's children are specified. The callback modules implements one
callback, init/1
, with single argument Args
. init/1
should return
{ok, {QueueSpec, ValveSpec, [MeterSpec]}}
or ignore
. QueueSpec
is the
sbroker_queue
specification, ValveSpec
is the sregulator_valve
specification and MeterSpec
is a sbroker_meter
specification. There can
be any number of meters but a meter module can only be included once. All
three take the same format: {Module, Args}
, where Module
is the callback
module and Args
the arguments term for the module. In the case of ignore
the regulator is not started and start_link
returns ignore
. As the
callback modules are defined in the init/1
callback a regulator supports
the dynamic
modules supervisor child specification.
For example:
-module(sregulator_example). -behaviour(sregulator). -export([start_link/0]). -export([ask/0]). -export([continue/1]). -export([done/1]). -export([init/1]). start_link() -> sregulator:start_link({local, ?MODULE}, ?MODULE, [], []). ask() -> case sregulator:ask(?MODULE) of {go, Ref, _, _, _} -> {ok, Ref}; {drop, _} -> {error, dropped} end. continue(Ref) -> case sregulator:continue(?MODULE, Ref, 5000) of {go, Ref, _, _, _} -> {ok, Ref}; {done, _} -> {error, dropped}; {not_found, _} -> {error, not_found} end. done(Ref init([]) -> QueueSpec = {sbroker_codel_queue, {out, 50, 500, drop_r, 64}}, ValveSpec = {sregulator_open_valve, 30}, MeterSpec = {sbroker_overload_meter, {50, 500, {?MODULE, overload}}}, {ok, {QueueSpec, ValveSpec, [MeterSpec]}}.
debug_option() = trace | log | {log, pos_integer()} | statistics | {log_to_file, file:filename()} | {install, {function(), any()}}
handler_spec() = {module(), any()}
name() = {local, atom()} | {global, any()} | {via, module(), any()}
regulator() = pid() | atom() | {atom(), node()} | {global, any()} | {via, module(), any()}
start_option() = {debug, debug_option()} | {timeout, timeout()} | {spawn_opt, [proc_lib:spawn_option()]} | {read_time_after, non_neg_integer() | infinity}
start_return() = {ok, pid()} | ignore | {error, any()}
ask/1 | Send a run request to the regulator, Regulator . |
async_ask/1 | Monitor the regulator and send an asynchronous run request. |
async_ask/2 | Send an asynchronous run request using tag, Tag . |
await/2 | Await the response to an asynchronous request idenitifed by Tag . |
cancel/3 | Cancel an asynchronous request. |
cast/2 | Update the valve in the regulator without waiting for the regulator to handle the update. |
change_config/2 | Change the configuration of the regulator. |
continue/2 | Send a request to continue running using an existing lock reference,
Ref . |
done/3 | Inform the regulator the process has finished running and release the
lock, Ref . |
dynamic_ask/1 | Send a run request to the regulator, Regulator . |
len/2 | Get the length of the internal queue in the regulator, Regulator . |
nb_ask/1 | Send a run request to the regulator, Regulator , but do not enqueue the
request if not immediately allowed to run. |
size/2 | Get the number of processes holding a lock with the regulator,
Regulator . |
start_link/3 | Starts a regulator with callback module Module and argument Args ,
and regulator options Opts . |
start_link/4 | Starts a regulator with name Name , callback module Module and
argument Args , and regulator options Opts . |
update/3 | Synchronously update the valve in the regulator. |
ask(Regulator) -> Go | Drop
Send a run request to the regulator, Regulator
.
Returns {go, Ref, RegulatorPid, RelativeTIme, SojournTime}
on successfully
being allowed to run or {drop, SojournTime}
.
Ref
is the lock reference, which is a reference()
. RegulatorPid
is the
pid()
of the regulator process. RelativeTime
is the time difference
between when the request was sent and the message that opened the regulator's
valve was sent. SojournTime
is the approximate time spent in both the
regulator's message queue and internal queue.
RelativeTime
represents the SojournTime
without the overhead of the
regulator. The value measures the queue congestion without being effected by
the load of the regulator or node.
If RelativeTime
is positive, the request was enqueued in the internal queue
awaiting a message to open the value that was sent approximately
RelativeTime
ater this request was sent. Therefore SojournTime
minus
RelativeTime
is the latency, or overhead, of the regulator.
If RelativeTime
is negative, the regulator's valve was opened by a message
sent abs(RelativeTime)
before this request. Therefore SojournTime
is the
latency, or overhead, of the regulator.
RelativeTime
is 0
, the request was sent at approximately the same as
the message that open the regulator's valve.
async_ask(Regulator) -> {await, Tag, Process} | {drop, 0}
Monitor the regulator and send an asynchronous run request. Returns
{await, Tag, Process}
.
Tag
is a monitor reference()
that uniquely identifies the reply
containing the result of the request. Process
is the pid()
of the
regulator or {atom(), node()}
if the regulator is registered locally on a
different node.
The reply is of the form {Tag, Msg}
where Msg
is either
{go, Ref, RegulatorPid, RelativeTime, SojournTime}
or
{drop, SojournTime}
.
Ref
is the lock reference, which is a reference()
. RegulatorPid
is the
pid()
of the regulator process. RelativeTime
is the time difference
between when the request was sent and the message that opened the regulator's
valve was sent. SojournTime
is the approximate time spent in both the
regulator's message queue and internal queue.
Multiple asynchronous requests can be made from a single process to a
regulator and no guarantee is made of the order of replies. A process making
multiple requests can reuse the monitor reference for subsequent requests to
the same regulator process (Process
) using async_ask/2
.
via
module sprotector
returns
{drop, 0}
and does not send the request.
See also: async_ask/2, cancel/2.
async_ask(Regulator, To) -> {await, Tag, Process} | {drop, 0}
Send an asynchronous run request using tag, Tag
. Returns
{await, Tag, Process}
.
To
is a tuple containing the process, pid()
, to send the reply to and
Tag
, any()
, that idenitifes the reply containing the result of the
request. Process
is the pid()
of the regulator or {atom(), node()}
if
the regulator is registered locally on a different node.
async_ask/1
.
See also: async_ask/1, cancel/2.
await(Tag, Timeout) -> Go | Drop
Await the response to an asynchronous request idenitifed by Tag
.
Exits if a response is not received after Timeout
milliseconds.
DOWN
message is received with reference Tag
.
See also: async_ask/1, async_ask/2.
cancel(Regulator, Tag, Timeout) -> Count | false
Cancel an asynchronous request.
Returns the number of cancelled requests orfalse
if no requests exist with
tag Tag
. In the later case a caller may wish to check is message queue for
an existing reply.
See also: async_ask/1, async_ask/2.
cast(Regulator, Value) -> ok
Update the valve in the regulator without waiting for the regulator to handle the update.
Value
is an integer()
.
ok
.
change_config(Regulator, Timeout) -> ok | {error, Reason}
Change the configuration of the regulator. Returns ok
on success and
{error, Reason}
on failure, where Reason
is the reason for failure.
init/1
callback to get the new configuration. If
init/1
returns ignore
the config does not change.
continue(Regulator, Ref) -> Go | Stop | NotFound | Drop
Send a request to continue running using an existing lock reference,
Ref
. The request is not queued.
Returns {go, Ref, RegulatorPid, RelativeTime, SojournTime}
on successfully
being allowed to run, {stop, SojournTime}
when the process should stop
running or {not_found, SojournTime}
when the lock reference does not exist
on the regulator.
Ref
is the lock reference, which is a reference()
. RegulatorPid
is the
pid()
of the regulator process. RelativeTime
is the time difference
between when the request was sent and the message that opened the regulator's
valve was sent. SojournTime
is the approximate time spent in the
regulator's message queue.
via
module sprotector
returns
{drop, 0}
and does not send the request. In this situation the Ref
is
still a valid lock on the regulator.
See also: ask/1.
done(Regulator, Ref, Timeout) -> Stop | NotFound
Inform the regulator the process has finished running and release the
lock, Ref
.
Returns {stop, SojournTime}
if the regulator acknowledged the process has
stopped running or {not_found, SojournTime}
if the lock reference, Ref
,
does not exist on the regulator.
SojournTime
is the time the request spent in the regulator's message queue.
See also: ask/1.
dynamic_ask(Regulator) -> Go | Await | Drop
Send a run request to the regulator, Regulator
. If not immediately
allowed to run the request is converted to an async_ask/1
.
Returns {go, Ref, RegulatorPid, RelativeTime, SojournTime}
on successfully
being allowed to run or {await, Tag, RegulatorPid}
.
Ref
is the lock reference, which is a reference()
. RegulatorPid
is the
pid()
of the regulator process. RelativeTime
is the time difference
between when the request was sent and the message that opened the regulator's
valve was sent. SojournTime
is the approximate time spent in the
regulator's message queue. Tag
is a monitor reference, as returned by
async_ask/1
.
via
module sprotector
returns
{drop, 0}
and does not send the request.
See also: async_ask/1, nb_ask/1.
len(Regulator, Timeout) -> Length
Get the length of the internal queue in the regulator, Regulator
.
nb_ask(Regulator) -> Go | Drop
Send a run request to the regulator, Regulator
, but do not enqueue the
request if not immediately allowed to run.
Returns {go, Ref, RegulatorPid, RelativeTime, SojournTime}
on successfully
being allowed to run or {drop, SojournTime}
.
Ref
is the lock reference, which is a reference()
. RegulatorPid
is the
pid()
of the regulator process. RelativeTime
is the time difference
between when the request was sent and the message that opened the regulator's
valve was sent. SojournTime
is the approximate time spent in the
regulator's message queue.
via
module sprotector
returns
{drop, 0}
and does not send the request.
See also: ask/1.
size(Regulator, Timeout) -> Size
Get the number of processes holding a lock with the regulator,
Regulator
.
start_link(Module, Args, Opts) -> StartReturn
Starts a regulator with callback module Module
and argument Args
,
and regulator options Opts
.
Opts
is a proplist
and supports debug
, timeout
and spawn_opt
used
by gen_server
and gen_fsm
. read_time_after
sets the number of requests
when a cached time is stale and the time is read again. Its value is
non_neg_integer()
or infinity
and defaults to 16
.
See also: gen_server:start_link/3.
start_link(Name, Module, Args, Opts) -> StartReturn
Starts a regulator with name Name
, callback module Module
and
argument Args
, and regulator options Opts
.
See also: start_link/3.
update(Regulator, Value, Timeout) -> ok
Synchronously update the valve in the regulator.
Value
is an integer()
and Timeout
is the timout, timeout()
, to wait
in milliseconds for the regulator to reply to the update.
ok
.
Generated by EDoc, Sep 29 2016, 17:17:28.