use crate::events::RouterEvent;
use crate::selection::SelectionStrategy;
use tower_resilience_core::events::{EventListeners, FnListener};
#[derive(Clone)]
pub struct RouterConfig {
pub(crate) name: String,
pub(crate) strategy: SelectionStrategy,
pub(crate) event_listeners: EventListeners<RouterEvent>,
}
pub struct WeightedRouterBuilder<S> {
backends: Vec<(S, u32)>,
name: String,
strategy: SelectionStrategy,
event_listeners: EventListeners<RouterEvent>,
}
impl<S> WeightedRouterBuilder<S> {
pub fn new() -> Self {
Self {
backends: Vec::new(),
name: "weighted_router".to_string(),
strategy: SelectionStrategy::default(),
event_listeners: EventListeners::new(),
}
}
pub fn route(mut self, service: S, weight: u32) -> Self {
self.backends.push((service, weight));
self
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
pub fn strategy(mut self, strategy: SelectionStrategy) -> Self {
self.strategy = strategy;
self
}
pub fn deterministic(mut self) -> Self {
self.strategy = SelectionStrategy::Deterministic;
self
}
pub fn random(mut self) -> Self {
self.strategy = SelectionStrategy::Random;
self
}
pub fn on_request_routed<F>(mut self, f: F) -> Self
where
F: Fn(usize, u32) + Send + Sync + 'static,
{
self.event_listeners.add(FnListener::new(move |event| {
let RouterEvent::RequestRouted {
backend_index,
backend_weight,
..
} = event;
f(*backend_index, *backend_weight);
}));
self
}
pub fn build(self) -> crate::WeightedRouter<S> {
assert!(
!self.backends.is_empty(),
"at least one backend is required"
);
for (i, (_, weight)) in self.backends.iter().enumerate() {
assert!(
*weight > 0,
"backend {i} has weight 0; all weights must be positive"
);
}
let config = RouterConfig {
name: self.name,
strategy: self.strategy,
event_listeners: self.event_listeners,
};
crate::WeightedRouter::new(self.backends, config)
}
}
impl<S> Default for WeightedRouterBuilder<S> {
fn default() -> Self {
Self::new()
}
}