Skip to main content

tuwunel_service/federation/
mod.rs

1mod execute;
2mod format;
3mod peer;
4mod rank;
5pub mod scheme;
6#[cfg(test)]
7mod tests;
8
9use std::{sync::Arc, time::Duration};
10
11use tuwunel_core::{Result, utils::exponential_backoff_streak_cap};
12use tuwunel_database::Map;
13
14use self::peer::MAX_BACKOFF;
15pub use self::{
16	peer::{Classification, ShouldAttempt},
17	rank::{Candidates, WhenAllBackedOff},
18};
19use crate::services::OnceServices;
20
21pub struct Service {
22	services: Arc<OnceServices>,
23	statuses: Arc<Map>,
24
25	/// Width of one peer-status bucket in seconds. Aligned with
26	/// `sender_timeout` so the streak count walking back across adjacent
27	/// buckets matches the sender's `consecutive_failures` notion at the
28	/// cutover.
29	window_secs: u64,
30
31	/// Walk-back cap = `ceil(sqrt(MAX_BACKOFF / window_secs))`. Beyond this
32	/// streak length the quadratic curve `window * n²` saturates at
33	/// [`MAX_BACKOFF`] and further steps cannot change the verdict.
34	n_max: u32,
35}
36
37impl crate::Service for Service {
38	fn build(args: &crate::Args<'_>) -> Result<Arc<Self>> {
39		let window_secs = args.server.config.sender_timeout.max(1);
40		let n_max = exponential_backoff_streak_cap(Duration::from_secs(window_secs), MAX_BACKOFF);
41
42		Ok(Arc::new(Self {
43			services: args.services.clone(),
44			statuses: args.db["servername_status"].clone(),
45			window_secs,
46			n_max,
47		}))
48	}
49
50	fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
51}