deepstrike_core/signals/
attention.rs1use crate::scheduler::tcb::TaskLifecycle;
2use crate::types::policy::SignalDisposition;
3use crate::types::signal::{RuntimeSignal, Urgency};
4
5pub struct UrgencyBasedPolicy;
7
8impl UrgencyBasedPolicy {
9 pub fn evaluate(&self, signal: &RuntimeSignal, lifecycle: TaskLifecycle) -> SignalDisposition {
10 if lifecycle.is_terminal() {
11 return SignalDisposition::Queue;
12 }
13
14 match signal.urgency {
15 Urgency::Critical => {
16 if matches!(lifecycle, TaskLifecycle::Running | TaskLifecycle::Suspended) {
17 SignalDisposition::InterruptNow
18 } else {
19 SignalDisposition::Run
20 }
21 }
22 Urgency::High => {
23 if matches!(lifecycle, TaskLifecycle::Running | TaskLifecycle::Suspended) {
24 SignalDisposition::Interrupt
25 } else {
26 SignalDisposition::Run
27 }
28 }
29 Urgency::Normal => {
30 if matches!(lifecycle, TaskLifecycle::Ready) {
31 SignalDisposition::Run
32 } else {
33 SignalDisposition::Queue
34 }
35 }
36 Urgency::Low => SignalDisposition::Observe,
37 }
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use crate::scheduler::tcb::TaskLifecycle;
45 use crate::types::result::TerminationReason;
46 use crate::types::signal::{SignalSource, SignalType};
47
48 #[test]
49 fn critical_signal_interrupts_running() {
50 let policy = UrgencyBasedPolicy;
51 let signal = RuntimeSignal::new(
52 SignalSource::Gateway,
53 SignalType::Alert,
54 Urgency::Critical,
55 "fire",
56 );
57 assert_eq!(
58 policy.evaluate(&signal, TaskLifecycle::Running),
59 SignalDisposition::InterruptNow
60 );
61 }
62
63 #[test]
64 fn low_signal_observed() {
65 let policy = UrgencyBasedPolicy;
66 let signal =
67 RuntimeSignal::new(SignalSource::Cron, SignalType::Event, Urgency::Low, "tick");
68 assert_eq!(
69 policy.evaluate(&signal, TaskLifecycle::Ready),
70 SignalDisposition::Observe
71 );
72 }
73
74 #[test]
75 fn normal_signal_runs_an_idle_nonterminal_task() {
76 let policy = UrgencyBasedPolicy;
77 let signal = RuntimeSignal::new(
78 SignalSource::Cron,
79 SignalType::Job,
80 Urgency::Normal,
81 "work ready",
82 );
83
84 assert_eq!(
85 policy.evaluate(&signal, TaskLifecycle::Ready),
86 SignalDisposition::Run
87 );
88 assert_eq!(
89 policy.evaluate(&signal, TaskLifecycle::Running),
90 SignalDisposition::Queue
91 );
92 }
93
94 #[test]
95 fn terminal_task_queues_signal_for_host_decision() {
96 let policy = UrgencyBasedPolicy;
97 let signal = RuntimeSignal::new(
98 SignalSource::Gateway,
99 SignalType::Alert,
100 Urgency::Critical,
101 "late signal",
102 );
103
104 assert_eq!(
105 policy.evaluate(&signal, TaskLifecycle::Done(TerminationReason::Completed),),
106 SignalDisposition::Queue
107 );
108 }
109}