Skip to main content

datum_cluster/
config.rs

1use std::{
2    net::{IpAddr, Ipv4Addr, SocketAddr},
3    time::Duration,
4};
5
6/// Configuration for one Datum cluster member.
7#[derive(Debug, Clone)]
8pub struct ClusterConfig {
9    /// Stable logical node id used by Datum control-plane APIs.
10    pub node_id: String,
11    /// Akka-style role labels advertised in membership gossip.
12    pub roles: Vec<String>,
13    /// Local UDP address used for membership gossip.
14    pub bind_addr: SocketAddr,
15    /// Address peers should use to contact this node. If the port is `0`, the
16    /// bound UDP port is substituted at startup.
17    pub advertise_addr: SocketAddr,
18    /// DCP agent address peers should use for node-to-node control sessions.
19    ///
20    /// `ClusterAgent` fills this from the bound DCP listener when it starts the
21    /// agent and membership together. Bare membership nodes may leave it empty.
22    pub agent_addr: Option<SocketAddr>,
23    /// Seed node UDP addresses. The seed identity is resolved by foca from the
24    /// first announce reply, so only addresses are required here.
25    pub seed_nodes: Vec<SocketAddr>,
26    /// Foca probe period and periodic gossip cadence.
27    pub gossip_interval: Duration,
28    /// Direct probe round-trip timeout before foca asks indirect probes.
29    pub probe_timeout: Duration,
30    /// Foca suspect-to-down timeout. Keep this longer than the downing timeout
31    /// when `TimeoutDowning` should make the public downing decision first.
32    pub suspect_timeout: Duration,
33    /// Default timeout used by [`crate::TimeoutDowning`].
34    pub downing_timeout: Duration,
35    /// How long foca remembers down identities before accepting the exact same
36    /// identity again. New incarnations can rejoin before this expires.
37    pub remove_down_after: Duration,
38    /// Maximum UDP packet size foca will produce and consume.
39    pub max_packet_size: usize,
40    /// Bounded event-feed capacity for [`crate::MemberEvent`] subscribers.
41    pub event_buffer: usize,
42    /// Timeout for `leave()` and `abort()` oneshot replies.
43    pub request_timeout: Duration,
44}
45
46impl ClusterConfig {
47    /// Create a config with loopback defaults and no seed nodes.
48    #[must_use]
49    pub fn new(node_id: impl Into<String>) -> Self {
50        Self {
51            node_id: node_id.into(),
52            ..Self::default()
53        }
54    }
55
56    /// Return a copy using the supplied roles.
57    #[must_use]
58    pub fn with_roles(mut self, roles: impl IntoIterator<Item = impl Into<String>>) -> Self {
59        self.roles = roles.into_iter().map(Into::into).collect();
60        self
61    }
62
63    /// Return a copy using the supplied seed-node addresses.
64    #[must_use]
65    pub fn with_seed_nodes(mut self, seed_nodes: impl IntoIterator<Item = SocketAddr>) -> Self {
66        self.seed_nodes = seed_nodes.into_iter().collect();
67        self
68    }
69
70    pub(crate) fn normalized_roles(&self) -> Vec<String> {
71        let mut roles = self
72            .roles
73            .iter()
74            .map(|role| role.trim().to_owned())
75            .filter(|role| !role.is_empty())
76            .collect::<Vec<_>>();
77        roles.sort();
78        roles.dedup();
79        roles
80    }
81}
82
83impl Default for ClusterConfig {
84    fn default() -> Self {
85        let loopback = IpAddr::V4(Ipv4Addr::LOCALHOST);
86        Self {
87            node_id: format!("datum-node-{}", std::process::id()),
88            roles: Vec::new(),
89            bind_addr: SocketAddr::new(loopback, 0),
90            advertise_addr: SocketAddr::new(loopback, 0),
91            agent_addr: None,
92            seed_nodes: Vec::new(),
93            gossip_interval: Duration::from_millis(250),
94            probe_timeout: Duration::from_millis(75),
95            suspect_timeout: Duration::from_secs(2),
96            downing_timeout: Duration::from_millis(500),
97            remove_down_after: Duration::from_secs(60),
98            max_packet_size: 1400,
99            event_buffer: 256,
100            request_timeout: Duration::from_secs(5),
101        }
102    }
103}