Skip to main content

forge_core/cluster/
traits.rs

1use super::node::NodeId;
2use super::roles::LeaderRole;
3
4/// Information about the cluster.
5#[derive(Debug, Clone)]
6pub struct ClusterInfo {
7    /// Cluster name.
8    pub name: String,
9    /// Total number of registered nodes.
10    pub total_nodes: usize,
11    /// Number of active nodes.
12    pub active_nodes: usize,
13    /// Number of draining nodes.
14    pub draining_nodes: usize,
15    /// Number of dead nodes.
16    pub dead_nodes: usize,
17    /// Current scheduler leader node ID.
18    pub scheduler_leader: Option<NodeId>,
19}
20
21impl ClusterInfo {
22    pub fn empty(name: impl Into<String>) -> Self {
23        Self {
24            name: name.into(),
25            total_nodes: 0,
26            active_nodes: 0,
27            draining_nodes: 0,
28            dead_nodes: 0,
29            scheduler_leader: None,
30        }
31    }
32}
33
34/// Leadership information for a role.
35#[derive(Debug, Clone)]
36pub struct LeaderInfo {
37    pub role: LeaderRole,
38    pub node_id: NodeId,
39    pub acquired_at: chrono::DateTime<chrono::Utc>,
40    pub lease_until: chrono::DateTime<chrono::Utc>,
41}
42
43impl LeaderInfo {
44    pub fn is_valid(&self) -> bool {
45        self.lease_until > chrono::Utc::now()
46    }
47}
48
49#[cfg(test)]
50#[allow(clippy::unwrap_used, clippy::indexing_slicing)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_cluster_info_empty() {
56        let info = ClusterInfo::empty("test-cluster");
57        assert_eq!(info.name, "test-cluster");
58        assert_eq!(info.total_nodes, 0);
59        assert_eq!(info.active_nodes, 0);
60        assert!(info.scheduler_leader.is_none());
61    }
62
63    #[test]
64    fn test_leader_info_validity() {
65        let node_id = NodeId::new();
66        let info = LeaderInfo {
67            role: LeaderRole::Scheduler,
68            node_id,
69            acquired_at: chrono::Utc::now(),
70            lease_until: chrono::Utc::now() + chrono::Duration::minutes(1),
71        };
72        assert!(info.is_valid());
73
74        let expired_info = LeaderInfo {
75            role: LeaderRole::Scheduler,
76            node_id,
77            acquired_at: chrono::Utc::now() - chrono::Duration::minutes(5),
78            lease_until: chrono::Utc::now() - chrono::Duration::minutes(1),
79        };
80        assert!(!expired_info.is_valid());
81    }
82}