RpcLoadBalancer (rpc_load_balancer v0.3.6)

Copy Markdown View Source

Distributed RPC load balancer built on :pg.

Acts as a per-instance Supervisor that starts the selection algorithm's children and the RpcLoadBalancer.LoadBalancer GenServer for a single load balancer. Also provides the public API for node selection, RPC calls/casts, random-node helpers, and low-level :erpc wrappers.

Shared caches are owned by the application supervisor, not by individual load balancers.

Starting a load balancer

RpcLoadBalancer.start_link(
  name: :my_lb,
  selection_algorithm: RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.WeightedRoundRobin,
  algorithm_opts: [weights: %{:"worker1@host" => 3, :"worker2@host" => 1}]
)

Or define a named module with use RpcLoadBalancer — see __using__/1.

Options

  • :name (required) — balancer name; also the :pg group name
  • :selection_algorithm — module implementing RpcLoadBalancer.LoadBalancer.SelectionAlgorithm (default: Random)
  • :algorithm_opts — forwarded to the algorithm's init/2 and child_specs/2
  • :node_match_list:all or a list of strings/regexes; controls whether this node registers as a target (default: :all)
  • :drain_timeout — ms to wait for in-flight calls on shutdown (default: 15_000)

Summary

Types

name()

@type name() :: atom()

Functions

__using__(opts)

(macro)

Defines a named load balancer module exposing the full RpcLoadBalancer interface bound to a fixed configuration.

defmodule MyApp.LoadBalancer do
  use RpcLoadBalancer,
    selection_algorithm: RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.HashRing,
    node_match_list: ["my_app"]
end

Supervise it directly (children = [MyApp.LoadBalancer]) and call the same functions as RpcLoadBalancer, with :load_balancer set to the using module automatically:

MyApp.LoadBalancer.call(node(), Mod, :fun, args, key: id)
MyApp.LoadBalancer.select_node(key: id)
MyApp.LoadBalancer.get_members()

The use options are forwarded to RpcLoadBalancer.start_link/1 with :name set to the using module. start_link/1 and child_spec/1 accept a keyword list of runtime overrides.

call(node, module, fun, args, opts \\ [])

@spec call(node(), module(), atom(), [any()], keyword()) :: ErrorMessage.t_res(any())

call_on_random_node(node_filter, module, fun, args, opts \\ [])

@spec call_on_random_node(
  String.t() | Regex.t(),
  module(),
  atom(),
  [any()],
  keyword()
) ::
  ErrorMessage.t_res(any())

cast(node, module, fun, args, opts \\ [])

@spec cast(node(), module(), atom(), [term()], keyword()) ::
  :ok | {:error, ErrorMessage.t()}

cast_on_random_node(node_filter, module, fun, args, opts \\ [])

@spec cast_on_random_node(
  String.t() | Regex.t(),
  module(),
  atom(),
  [any()],
  keyword()
) ::
  :ok | {:error, ErrorMessage.t()}

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

get_members(load_balancer_name)

@spec get_members(name()) :: {:ok, [node()]} | {:error, ErrorMessage.t()}

select_node(load_balancer_name, opts \\ [])

@spec select_node(
  name(),
  keyword()
) :: {:ok, node()} | {:error, ErrorMessage.t()}

start_link(opts)

@spec start_link(keyword()) :: Supervisor.on_start()