aion_server/worker/queue_service/
census.rs1use std::time::Duration;
8
9use super::declarations::QueueDeclaration;
10use super::taxonomy::QueueServiceReason;
11
12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
15pub struct PoolCensus {
16 pub workers_in_pool: usize,
18 pub workers_serving_activity: usize,
20 pub compatible_workers: usize,
23 pub last_compatible_poller_age: Option<Duration>,
28}
29
30impl PoolCensus {
31 #[must_use]
33 pub const fn is_served(&self) -> bool {
34 self.compatible_workers > 0
35 }
36}
37
38#[must_use]
56pub fn classify(declaration: QueueDeclaration, census: &PoolCensus) -> Option<QueueServiceReason> {
57 if census.is_served() {
58 return None;
59 }
60 if declaration == QueueDeclaration::NotDeclared {
61 return Some(QueueServiceReason::NoQueueDeclaration);
62 }
63 if census.workers_in_pool > 0 {
64 return Some(QueueServiceReason::PollersIncompatible);
65 }
66 Some(QueueServiceReason::NoLivePollers)
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn a_served_address_is_not_classified() {
75 let census = PoolCensus {
76 workers_in_pool: 1,
77 workers_serving_activity: 1,
78 compatible_workers: 1,
79 last_compatible_poller_age: Some(Duration::ZERO),
80 };
81 assert_eq!(classify(QueueDeclaration::Declared, &census), None);
82 assert_eq!(classify(QueueDeclaration::NotDeclared, &census), None);
83 }
84
85 #[test]
86 fn an_undeclared_queue_is_structural() {
87 assert_eq!(
88 classify(QueueDeclaration::NotDeclared, &PoolCensus::default()),
89 Some(QueueServiceReason::NoQueueDeclaration)
90 );
91 }
92
93 #[test]
94 fn an_empty_pool_on_a_declared_queue_has_no_live_pollers() {
95 assert_eq!(
96 classify(QueueDeclaration::Declared, &PoolCensus::default()),
97 Some(QueueServiceReason::NoLivePollers)
98 );
99 }
100
101 #[test]
102 fn an_unknowable_declaration_never_produces_a_structural_refusal() {
103 assert_eq!(
104 classify(QueueDeclaration::Unknown, &PoolCensus::default()),
105 Some(QueueServiceReason::NoLivePollers)
106 );
107 }
108
109 #[test]
110 fn pollers_that_do_not_cover_the_activity_are_incompatible() {
111 let census = PoolCensus {
112 workers_in_pool: 2,
113 workers_serving_activity: 0,
114 compatible_workers: 0,
115 last_compatible_poller_age: None,
116 };
117 assert_eq!(
118 classify(QueueDeclaration::Declared, &census),
119 Some(QueueServiceReason::PollersIncompatible)
120 );
121 }
122
123 #[test]
124 fn pollers_off_the_pinned_node_are_incompatible() {
125 let census = PoolCensus {
126 workers_in_pool: 1,
127 workers_serving_activity: 1,
128 compatible_workers: 0,
129 last_compatible_poller_age: Some(Duration::from_secs(9)),
130 };
131 assert_eq!(
132 classify(QueueDeclaration::Declared, &census),
133 Some(QueueServiceReason::PollersIncompatible)
134 );
135 }
136}