sbroker
=======
Sojourn Broker - process broker for matchmaking between two groups of processes
using sojourn time based active queue management to prevent congestion.
Introduction
------------
`sbroker` provides a simple interface to match processes. One party
calls `sbroker:ask/1` and the counterparty `sbroker:ask_r/1`. If a match
is found both return `{go, Ref, Pid, RelativeTime, SojournTime}`. `Ref` is the
transaction reference. `Pid` is the other process in the match, which can be
changed by using `sbroker:ask/2` and `sbroker:ask_r/2`. `SojournTime` is the
time spent waiting for a match and `RelativeTime` is the theoretical sojourn
time if using the sbroker had no overhead. If no match is found, returns
`{drop, SojournTime}`. The time unit for `SojournTime` and `RelativeTime` is set
by the `time_unit` start option to a broker, defaulting to the VM's native unit.
Processes calling `sbroker:ask/1` are only matched with a process calling
`sbroker:ask_r/1` and vice versa.
Usage
-----
`sbroker` provides configurable queues defined by `sbroker:queue_spec()`s. A
`queue_spec()` takes the form:
```erlang
{Module, Args}
```
`Module` is an `sbroker_queue` callback module to queue. The following callback
modules are provided: `sbroker_drop_queue`, `sbroker_timeout_queue` and
`sbroker_codel_queue`.
`Args` is the argument passed to the callback module. Information about
the different backends and their arguments are avaliable in the
documentation.
An `sbroker` is started using `sbroker:start_link/3,4`:
```erlang
sbroker:start_link(Module, Args, Opts).
sbroker:start_link(Name, Module, Args, Opts).
```
The sbroker will call `Module:init(Args)`, which should return the specification
for the sbroker:
```erlang
init(_) ->
{ok, {AskQueueSpec, AskRQueueSpec, Timeout}}.
```
`AskQueueSpec` is the `queue_spec` for the queue containing processes calling
`ask/1`. The queue is referred to as the `ask` queue. Similarly
`AskRQueueSpec` is the `queue_spec` for the queue contaning processes calling
`ask_r/1`, and the queue is referred to as the `ask_r` queue.
`Timeout` is the timeout, in milliseconds, that the broker polls the
active queue after a period of inactivity. Note that timeout queue management
can occur on every enqueue and dequeue, and is not reliant on the `Timeout`.
Setting a suitable timeout ensures that active queue management can occur if no
processes are enqueued or dequeued for a period of time.
For example:
```erlang
-module(sbroker_example).
-behaviour(sbroker).
-export([start_link/0]).
-export([init/1]).
start_link() ->
sbroker:start_link(?MODULE, undefined, [{time_unit, milli_seconds}]).
init(_) ->
QueueSpec = {sbroker_timeout_queue, {out, 200, drop, 16}},
{ok, {QueueSpec, QueueSpec, 100}}.
```
`sbroker_example:start_link/0` will start an `sbroker` with queues configured by
`QueueSpec`.
This configuration uses the `sbroker_timeout_queue` callback module which drops
requests when they have been in the queue for longer than a time limit - in this
case `200` milliseconds. `out` sets the queue to `FIFO`. `drop` sets the queue
to drop processes from the head of the queue (head drop) when the maximum size
(`16`) is reached. The broker timeout is `100` milliseconds, which means that
queue management is applied to the active queue after `100` milliseconds of
inactivity. This value is always in milliseconds, regardless of the
`time_unit` in the start options.
To use this `sbroker`:
```erlang
{ok, Broker} = sbroker_example:start_link(),
Pid = spawn_link(fun() -> sbroker:ask_r(Broker) end),
{go, _Ref, Pid, _, _} = sbroker:ask(Broker).
```
Build
-----
Rebar:
```
rebar compile
```
Rebar3:
```
rebar3 compile
```
Documentation
-------------
Available at: http://hexdocs.pm/sbroker/
Rebar builds documentation:
```
rebar doc
```
Then visit `doc/index.html`.
Test
----
Testing requires rebar3:
```
rebar3 ct
```
License
-------
Apache License, Version 2.0