loadwise_core/node.rs
1//! Traits for describing backend nodes and their observable properties.
2
3use std::fmt::Debug;
4use std::hash::Hash;
5
6/// A backend node that can be selected by a load balancing strategy.
7pub trait Node: Send + Sync {
8 /// Unique identifier type for this node.
9 type Id: Eq + Hash + Clone + Debug + Send + Sync;
10
11 /// Returns a reference to this node's unique identifier.
12 fn id(&self) -> &Self::Id;
13}
14
15/// Exposes a weight for weighted strategies. Higher weight = more traffic.
16pub trait Weighted: Send + Sync {
17 /// Relative weight of this node. A node with weight 4 receives roughly
18 /// twice the traffic of a node with weight 2.
19 fn weight(&self) -> u32;
20}
21
22/// Exposes a load score for load-aware strategies. Lower is better.
23pub trait LoadMetric: Send + Sync {
24 /// Current load score. Strategies like [`LeastLoad`](crate::strategy::LeastLoad)
25 /// and [`PowerOfTwoChoices`](crate::strategy::PowerOfTwoChoices) use this to
26 /// prefer less-loaded nodes.
27 ///
28 /// Should return a finite, non-NaN value. With [`LeastLoad`](crate::strategy::LeastLoad),
29 /// a NaN node is never selected (`NaN < x` is always `false`).
30 /// With [`PowerOfTwoChoices`](crate::strategy::PowerOfTwoChoices), a NaN node **may**
31 /// be selected because P2C uses `<=` (`x <= NaN` is `false`, causing the NaN node
32 /// to win the comparison).
33 fn load_score(&self) -> f64;
34}
35
36/// Exposes remaining capacity for quota-aware strategies. Higher is better.
37///
38/// Complementary to [`LoadMetric`] (which exposes current load — lower is better):
39/// - `LoadMetric`: "how busy is this node?" → lower wins
40/// - `RateMetric`: "how much capacity remains?" → higher wins
41///
42/// A node can implement both — a node may have low load but little remaining
43/// quota, or high load but ample quota.
44pub trait RateMetric: Send + Sync {
45 /// Remaining capacity as a ratio: `0.0` = exhausted, `1.0` = fully available.
46 fn remaining_ratio(&self) -> f64;
47}