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    /// Create empty cluster info.
23    pub fn empty(name: impl Into<String>) -> Self {
24        Self {
25            name: name.into(),
26            total_nodes: 0,
27            active_nodes: 0,
28            draining_nodes: 0,
29            dead_nodes: 0,
30            scheduler_leader: None,
31        }
32    }
33}
34
35/// Leadership information for a role.
36#[derive(Debug, Clone)]
37pub struct LeaderInfo {
38    /// The leader role.
39    pub role: LeaderRole,
40    /// Node ID of the leader.
41    pub node_id: NodeId,
42    /// When leadership was acquired.
43    pub acquired_at: chrono::DateTime<chrono::Utc>,
44    /// When the lease expires.
45    pub lease_until: chrono::DateTime<chrono::Utc>,
46}
47
48impl LeaderInfo {
49    /// Check if the lease is still valid.
50    pub fn is_valid(&self) -> bool {
51        self.lease_until > chrono::Utc::now()
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn test_cluster_info_empty() {
61        let info = ClusterInfo::empty("test-cluster");
62        assert_eq!(info.name, "test-cluster");
63        assert_eq!(info.total_nodes, 0);
64        assert_eq!(info.active_nodes, 0);
65        assert!(info.scheduler_leader.is_none());
66    }
67
68    #[test]
69    fn test_leader_info_validity() {
70        let node_id = NodeId::new();
71        let info = LeaderInfo {
72            role: LeaderRole::Scheduler,
73            node_id,
74            acquired_at: chrono::Utc::now(),
75            lease_until: chrono::Utc::now() + chrono::Duration::minutes(1),
76        };
77        assert!(info.is_valid());
78
79        let expired_info = LeaderInfo {
80            role: LeaderRole::Scheduler,
81            node_id,
82            acquired_at: chrono::Utc::now() - chrono::Duration::minutes(5),
83            lease_until: chrono::Utc::now() - chrono::Duration::minutes(1),
84        };
85        assert!(!expired_info.is_valid());
86    }
87}