// The gRPC client load-balancing policy (← gRPC's `pick_first` / `round_robin`): given the set of
// addresses a resolver produced for a target, decide which one the next call uses. This is the pure
// decision core of the Channel client's LB layer; the Channel drives it to spread calls across the
// connections it dials. `pick_first` always returns the first address (a single connection);
// `round_robin` cycles through them so load spreads evenly.
///|
/// A client-side load-balancing policy (← gRPC `loadBalancingConfig`).
pub(all) enum LbPolicy {
PickFirst
RoundRobin
} derive(Eq, Debug)
///|
/// A load balancer over a resolver's addresses, applying an `LbPolicy` to choose the next one.
pub struct LoadBalancer {
addresses : Array[String]
policy : LbPolicy
mut cursor : Int
}
///|
/// A balancer over `addresses` (each a `host:port`) using `policy` (default `PickFirst`).
pub fn LoadBalancer::new(
addresses : Array[String],
policy? : LbPolicy = PickFirst,
) -> LoadBalancer {
{ addresses, policy, cursor: 0 }
}
///|
/// The address the next call should use, or `None` when the resolver produced none. `PickFirst`
/// always returns the first address; `RoundRobin` returns each in turn, wrapping around.
pub fn LoadBalancer::pick(self : LoadBalancer) -> String? {
let n = self.addresses.length()
guard n > 0 else { return None }
match self.policy {
PickFirst => Some(self.addresses[0])
RoundRobin => {
let address = self.addresses[self.cursor % n]
self.cursor = (self.cursor + 1) % n
Some(address)
}
}
}
///|
/// The number of addresses the balancer is choosing among.
pub fn LoadBalancer::size(self : LoadBalancer) -> Int {
self.addresses.length()
}