moonbitstack/moonzero/balance does not have a README file

    Resolve

    type Resolve = (String) -> Array[
    Endpoint
    ]

    The instances of a service. It runs on every call, so it must answer without waiting: a program passes @moonsd.View::endpoints here and runs View::follow in a task of its own.

    Balancer

    pub(all) enum Balancer {
    RoundRobin(
    RoundRobin
    )
    PickFirst
    Weighted(
    Weighted
    )
    P2c(P2c)
    }

    How a load-balanced channel chooses: in turn, in proportion to Endpoint::weight, or always the first (gRPC's pick_first). Weighted keeps its credit by Endpoint::id.

    Balancer::p2c

    Power-of-two-choices over measured load.

    Balancer::pick

    One of endpoints, or None if there is nothing to choose.

    Balancer::report

    fn Balancer::report(self : Balancer, endpoint :
    Endpoint
    , started_ms : Int64, ok : Bool) -> Unit

    Report how a call to endpoint ended, so a load-aware balancer can move its numbers. Balancers that choose without feedback ignore it.

    Balancer::round_robin

    fn Balancer::round_robin() -> Balancer

    Instances in turn, from the first.

    Balancer::weighted

    fn Balancer::weighted() -> Balancer

    Instances by weight, with no credit yet.

    LoadBalancedChannel

    pub struct LoadBalancedChannel {
    resolve : (String) -> Array[
    Endpoint
    ]
    cluster : RpcCluster
    balancer : Balancer
    service : String
    clock :
    Clock

    }

    A load-balanced zRPC client (← go-zero's zrpc.Client over a discovery target): it resolves a service through Resolve, picks a live instance with the Balancer, dials it on the RpcCluster, and makes the call. The whole resolve→balance→dial→call path runs per call, so instances registering or deregistering between calls take effect on the next one.

    LoadBalancedChannel::balancer

    The balancer this channel chooses with, so a caller can read a load-aware picker's numbers.

    LoadBalancedChannel::call

    fn LoadBalancedChannel::call(self : LoadBalancedChannel, path : String, request : Bytes) -> Result[Bytes,
    Status
    ] raise

    Make a unary call to path, resolving and balancing to a live instance first.

    LoadBalancedChannel::call_bidi_streaming

    fn LoadBalancedChannel::call_bidi_streaming(self : LoadBalancedChannel, path : String, requests : Array[Bytes]) -> Result[Array[Bytes],
    Status
    ] raise

    Make a bidirectional-streaming call to path, resolving and balancing to a live instance first, then driving the whole requests exchange to completion.

    LoadBalancedChannel::call_server_streaming

    fn LoadBalancedChannel::call_server_streaming(self : LoadBalancedChannel, path : String, request : Bytes) -> Result[Array[Bytes],
    Status
    ] raise

    Make a server-streaming call to path, resolving and balancing to a live instance first.

    LoadBalancedChannel::new

    fn LoadBalancedChannel::new(resolve : (String) -> Array[
    Endpoint
    ], cluster : RpcCluster, service : String, balancer? : Balancer, clock? :
    Clock
    ) -> LoadBalancedChannel

    Build a load-balanced channel for service over a Resolve interface, dialing through cluster with balancer (round-robin by default).

    P2c

    pub struct P2c {
    conf : P2cConf
    clock :
    Clock

    nodes : Map[String, P2cNode]
    random : (Int) -> Int
    }

    The picker: one P2cNode per instance, keyed by Endpoint::id.

    P2c::done

    fn P2c::done(self : P2c, endpoint :
    Endpoint
    , started_ms : Int64, ok : Bool) -> Unit

    Record a finished call on endpoint: its in-flight count comes back down, and its lag and success count move towards this call by the weight the time since the previous update earns.

    P2c::new

    fn P2c::new(clock? :
    Clock
    , conf? : P2cConf, random? : (Int) -> Int) -> P2c

    A picker on clock. random answers an index in [0, n) and defaults to a counter-mixed generator, so a replay with a fixed clock and a fixed generator makes exactly the decisions the reference implementation makes.

    P2c::pick

    Pick an instance, or None when there is nothing to pick. The chosen node's in-flight count goes up, and done is what brings it back down.

    P2c::stats

    fn P2c::stats(self : P2c, endpoint :
    Endpoint
    ) -> (Int64, Int64, Int64)

    The node's numbers, for a test or a status endpoint.

    P2cConf

    pub(all) struct P2cConf {
    decay_ms : Int64
    force_pick_ms : Int64
    init_success : Double
    pick_times : Int
    }

    The constants the picker runs on. The defaults are the reference implementation's: a ten-second decay, a one-second forced pick, a thousand starting successes, and three attempts at finding a healthy pair.

    P2cNode

    pub struct P2cNode {
    lag : Double
    success : Double
    inflight : Int64
    requests : Int64
    last : Int64
    pick : Int64
    }

    One instance's numbers.

    RpcCluster

    pub struct RpcCluster {
    servers : Map[String,
    RpcServer
    ]
    }

    The in-process dial table: an endpoint address maps to the RpcServer listening there. It stands in for DNS resolution plus a socket dial in the in-process h2c transport — a real deployment opens a connection to the address instead of looking the server up here, but the resolve→balance→call path above it is the same.

    RpcCluster::add

    Bind the server reachable at endpoint's address.

    RpcCluster::dial

    Open a channel to the server bound at endpoint, or None if nothing is reachable there (a stale registry entry pointing at a gone instance).

    RpcCluster::new

    fn RpcCluster::new() -> RpcCluster

    An empty cluster.

    p2c_default

    let p2c_default : P2cConf

    The defaults.

    p2c_penalty

    let p2c_penalty : Int64

    The load a node reports when its computed one is zero: the largest 32-bit value, so it loses every comparison. Named rather than written where it is used because it is a decision, not an arithmetic detail.

    sqrt

    fn sqrt(x : Double) -> Double

    The square root of a non-negative number, by Newton's iteration.

    The standard library ships exp and the trigonometric functions but no square root for Double, and rounding a load to an integer to avoid one would change which of two instances is chosen.

    Source Files