1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Load balancing strategies and the [`Strategy`] trait.
//!
//! Built-in strategies:
//!
//! | Strategy | Requires | Algorithm |
//! |---------------------------|-----------------|----------------------------------------|
//! | [`RoundRobin`] | — | Sequential cycling |
//! | [`WeightedRoundRobin`] | `Weighted+Node` | Nginx smooth weighted round-robin |
//! | [`Random`] | — | Uniform random |
//! | [`WeightedRandom`] | `Weighted` | Proportional random |
//! | [`LeastLoad`] | `LoadMetric` | Pick lowest `load_score()` |
//! | [`PowerOfTwoChoices`] | `LoadMetric` | Random 2, pick lower load |
//! | [`ConsistentHash`] | `Node` | Virtual-node ring (cached) |
//! | [`MostAvailable`] | `RateMetric` | Pick highest remaining, epsilon tie-break |
//!
//! Combinators: [`WithFallback`], [`FallbackChain`].
pub use ;
pub use ConsistentHash;
pub use LeastLoad;
pub use MostAvailable;
pub use PowerOfTwoChoices;
pub use ;
pub use RoundRobin;
pub use WeightedRoundRobin;
use HashMap;
use Builder;
/// Context provided to strategies during node selection.
///
/// # Examples
///
/// ```
/// # extern crate loadwise_core as loadwise;
/// use loadwise::SelectionContext;
///
/// // Empty context (most strategies work fine without it).
/// let ctx = SelectionContext::default();
///
/// // With a hash key for consistent hashing.
/// let ctx = SelectionContext::builder()
/// .hash_key(42)
/// .build();
///
/// // With estimated request cost and tags.
/// let ctx = SelectionContext::builder()
/// .estimated_cost(150.0)
/// .tags([("model".into(), "gpt-4".into())].into())
/// .build();
///
/// assert_eq!(ctx.tag("model"), Some("gpt-4"));
///
/// // Exclude specific indices (e.g., retry after failure).
/// let ctx = SelectionContext::builder()
/// .exclude(vec![0, 2])
/// .build();
/// assert!(ctx.is_excluded(0));
/// assert!(!ctx.is_excluded(1));
/// ```
/// A load balancing strategy that selects a node from a list of candidates.
///
/// Returns the **index** of the selected node within the `candidates` slice.
/// Implementations must use interior mutability for any state (e.g., `AtomicUsize`).
///
/// # Examples
///
/// ```
/// # extern crate loadwise_core as loadwise;
/// use loadwise::{Strategy, SelectionContext};
/// use loadwise::strategy::RoundRobin;
///
/// let rr = RoundRobin::new();
/// let nodes = ["a", "b", "c"];
/// let ctx = SelectionContext::default();
///
/// assert_eq!(rr.select(&nodes, &ctx), Some(0));
/// assert_eq!(rr.select(&nodes, &ctx), Some(1));
/// assert_eq!(rr.select(&nodes, &ctx), Some(2));
/// assert_eq!(rr.select(&nodes, &ctx), Some(0)); // wraps around
/// ```
// ── internal helpers ──
use ;
use crateNode;
/// Order-sensitive fingerprint of a candidate set based on node IDs.
///
/// Used by strategies that cache internal state (e.g., hash ring, WRR weights)
/// to detect when the candidate list has changed.
///
/// NOTE: this is O(n) per call. For very large candidate lists, consider
/// letting the caller notify the strategy of changes instead of probing
/// every time. Good enough for typical pool sizes (10–100 nodes).
pub