# `RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.HashRing`
[🔗](https://github.com/MikaAK/rpc_load_balancer/blob/main/lib/rpc_load_balancer/load_balancer/selection_algorithm/hash_ring.ex#L1)

Consistent hash ring node selection algorithm powered by `libring`.

Routes requests to nodes based on a caller-provided `:key` option.
Each physical node is placed on the ring as virtual nodes (shards)
so that topology changes only redistribute a minimal number of keys.

Supports replica selection via `choose_nodes/4` — returns multiple
distinct nodes for a given key, useful for replication strategies.

When no key is provided, falls back to random selection.

Storage:
  * `:weight` (compile-time-ish — set once at `init/2`) lives in
    `:persistent_term` keyed by `{__MODULE__, lb_name, :weight}`.
    Write-once is the access pattern `:persistent_term` is designed
    for.
  * The ring itself lives in `HashRingCache` (ETS). It's rewritten
    on every `on_node_change` event, so PT would mean continuous
    global GC sweeps in clusters with steady flapping.

## Usage

    RpcLoadBalancer.start_link(
      name: :my_balancer,
      selection_algorithm: RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.HashRing,
      algorithm_opts: [weight: 200]
    )

    RpcLoadBalancer.select_node(:my_balancer, key: "user:123")

    # Replica selection goes through the dispatch layer:
    {:ok, members} = RpcLoadBalancer.get_members(:my_balancer)

    [primary, replica] =
      RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.choose_nodes(
        RpcLoadBalancer.LoadBalancer.SelectionAlgorithm.HashRing,
        :my_balancer,
        members,
        2,
        key: "user:123"
      )

## Options

- `:weight` — number of virtual nodes (shards) per physical node (default: 128)

---

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