# `RpcLoadBalancer`
[🔗](https://github.com/MikaAK/rpc_load_balancer/blob/main/lib/rpc_load_balancer.ex#L1)

Distributed RPC load balancer built on `:pg`.

Acts as a per-instance Supervisor that starts the caches and GenServer
needed for a single load balancer. Also provides the public API for
node selection, RPC calls/casts, and low-level `:erpc` wrappers.

## Starting a load balancer

    RpcLoadBalancer.start_link(
      name: :my_lb,
      selection_algorithm: RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.RoundRobin,
      algorithm_opts: [weights: %{node() => 1}]
    )

# `name`

```elixir
@type name() :: atom()
```

# `__using__`
*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`

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

# `call_on_random_node`

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

# `cast`

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

# `cast_on_random_node`

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

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `get_members`

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

# `select_node`

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

# `start_link`

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
