View Source WeightedRoundRobin (WeightedRoundRobin v0.1.3)

A local, decentralized and scalable weighted round-robin generator.

It allows developers to generate a sequence, evenly distributed, attending a predefined set of weights attributed to elements of any type. The take/2 function is guaranteed to be atomic and isolated.

Generators can have any number of pools, each under a different pool_name. The precision indicates how many precision digits you want at the generator output (so 100 indicates you want a two digits precision).

The application can have multiple instances of the generator, but in this case every function needs to be prefixed with the generator name, indicated as wrr.

Internally the pools are versioned using an ETS table for each version of the pool created with new_pool. Accesses hit the newer version first, and migrate from the older version to the newer version along the time. When a new generation is started, the oldest one is deleted by an internal GC.

Link to this section Summary

Functions

Returns a specification to start this module under a supervisor.

Delete a new pool from the generator.

Create a new pool under the generator.

Starts the weighted round-robin generator.

Take elements from the pool in a round-robin fashion.

Link to this section Types

Specs

key() :: any()

Specs

key_weights() :: [{key(), weight()}]

Specs

option() :: {:precision, precision()}

Specs

pool_name() :: any()

Specs

precision() :: non_neg_integer()

Specs

start_option() :: {:name, generator_name :: atom()}

Specs

weight() :: float()

Specs

wrr() :: atom()

Link to this section Functions

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

delete_pool(wrr \\ __MODULE__, pool_name)

View Source

Specs

delete_pool(wrr(), pool_name()) :: :ok

Delete a new pool from the generator.

It is not safe to call this function while serving other processes using take or concurrently with new_pool for the same pool.

Link to this function

gc(wrr \\ __MODULE__, gc_cleanup_min_timeout \\ 10000)

View Source

Executes the garbage collector.

Used when the automatic GC is disabled by passing :gc_interval as :infinity to start_link.

Link to this function

new_pool(pool_name, key_weights)

View Source

Specs

new_pool(pool_name(), key_weights()) :: :ok

Create a new pool under the generator.

It is safe to reconfigure pools by calling new_pool with different parameters, while take is being served at other processes.

Link to this function

new_pool(pool_name, key_weights, options)

View Source

Specs

new_pool(pool_name(), key_weights(), [option()]) :: :ok
Link to this function

new_pool(wrr, pool_name, key_weights, options \\ [])

View Source

Specs

new_pool(wrr(), pool_name(), key_weights(), [option()]) :: :ok

Specs

start_link([start_option()]) :: {:ok, pid()} | {:error, term()}

Starts the weighted round-robin generator.

You typically don't need to start the weighted round-robin generator, one is started automatically at application start, except if you explicitly say to not start one at your config:

config :wrr, start: false

So, manually it can be started as:

WeightedRoundRobin.start_link(name: MyApp.WeightedRoundRobin)

In your supervisor tree, you would write:

Supervisor.start_link([
  {WeightedRoundRobin, name: MyApp.WeightedRoundRobin}
], strategy: :one_for_one)

options

Options

The weighted round-robin generator requires the following key:

  • :name - the name of the generator and its tables

  • :gc_interval - If it is set, an integer > 0 is expected defining the interval time in milliseconds to garbage collection to run, deleting the older versions. If this option is not set, garbage collection is executed every 1 minute. If set to :infinity, garbage collection is never executed automatically and gc will need to be executed explicitly.

  • :gc_cleanup_min_timeout - An integer > 0 defining the min timeout in milliseconds for triggering the next cleanup.

Link to this function

take(wrr \\ __MODULE__, pool_name)

View Source

Specs

take(wrr(), pool_name()) :: key() | {:error, :not_found}

Take elements from the pool in a round-robin fashion.

examples

Examples

iex> :ok = WeightedRoundRobin.new_pool(:pool, [a: 0.1, b: 0.2, c: 1.0])
iex> dist = Enum.map(1..10_000, fn _ -> WeightedRoundRobin.take(:pool) end)
iex> %{a: 768, b: 1543, c: 7689} = Enum.frequencies(dist)