Skip to main content

consortium/
event.rs

1//! Event handler traits.
2//!
3//! Rust implementation of `ClusterShell.Event`.
4
5use std::any::Any;
6
7/// Trait for handling worker lifecycle events.
8///
9/// Implement any subset of these methods to react to events
10/// from workers and tasks. All methods have default no-op implementations.
11pub trait EventHandler: Send + Sync {
12    /// Called to indicate that a worker has just started.
13    fn ev_start(&mut self, _worker: &dyn Any) {}
14
15    /// Called for each node to indicate that a worker command for a
16    /// specific node (or key) has just started.
17    ///
18    /// *Changed in version 1.10:* in tree mode, `ev_pickup` now fires
19    /// only once a command can no longer be rerouted, so it fires at
20    /// most once per node.
21    fn ev_pickup(&mut self, _worker: &dyn Any, _node: &str) {}
22
23    /// Called to indicate that a worker has data to read from a specific
24    /// node (or key).
25    fn ev_read(&mut self, _worker: &dyn Any, _node: &str, _sname: &str, _msg: &str) {}
26
27    /// Called to indicate that a worker has error to read on stderr from
28    /// a specific node (or key).
29    ///
30    /// DEPRECATED: use ev_read instead and check if sname is 'stderr'
31    fn ev_error(&mut self, _worker: &dyn Any) {}
32
33    /// Called to indicate that some writing has been done by the worker to a
34    /// node on a given stream.
35    fn ev_written(&mut self, _worker: &dyn Any, _node: &str, _sname: &str, _size: usize) {}
36
37    /// Called for each node to indicate that a worker command for a specific
38    /// node has just finished.
39    fn ev_hup(&mut self, _worker: &dyn Any, _node: &str, _rc: i32) {}
40
41    /// Called to indicate that a worker has just finished.
42    fn ev_close(&mut self, _worker: &dyn Any, _timedout: bool) {}
43
44    /// Routing event (private). Called to indicate that a (meta)worker has just
45    /// updated one of its route path.
46    fn _ev_routing(&mut self, _worker: &dyn Any, _arg: &str) {}
47
48    /// Called to indicate that a message has been received on an EnginePort.
49    fn ev_msg(&mut self, _port: u16, _msg: &str) {}
50
51    /// Called to indicate that a timer is firing.
52    fn ev_timer(&mut self, _timer: &dyn Any) {}
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    /// Test that default implementations are callable for all methods
60    #[test]
61    fn test_default_impls_callable() {
62        struct DefaultHandler;
63
64        impl EventHandler for DefaultHandler {}
65
66        let mut handler = DefaultHandler;
67
68        // These should not panic - testing default no-op impls
69        handler.ev_start(&dyn_any_placeholder());
70        handler.ev_pickup(&dyn_any_placeholder(), "node1");
71        handler.ev_read(&dyn_any_placeholder(), "node1", "stdout", "hello");
72        handler.ev_error(&dyn_any_placeholder());
73        handler.ev_written(&dyn_any_placeholder(), "node1", "stdout", 100);
74        handler.ev_hup(&dyn_any_placeholder(), "node1", 0);
75        handler.ev_close(&dyn_any_placeholder(), false);
76        handler._ev_routing(&dyn_any_placeholder(), "route_data");
77        handler.ev_msg(8080, "message");
78        handler.ev_timer(&dyn_any_placeholder());
79    }
80
81    /// Test that custom implementations can override specific methods
82    #[test]
83    fn test_custom_overrides() {
84        struct CustomHandler {
85            pub start_count: usize,
86            pub close_count: usize,
87        }
88
89        impl CustomHandler {
90            fn new() -> Self {
91                Self {
92                    start_count: 0,
93                    close_count: 0,
94                }
95            }
96        }
97
98        impl EventHandler for CustomHandler {
99            fn ev_start(&mut self, _worker: &dyn Any) {
100                self.start_count += 1;
101            }
102
103            fn ev_close(&mut self, _worker: &dyn Any, timedout: bool) {
104                self.close_count += 1;
105                assert!(!timedout, "Expected no timeout in this test");
106            }
107        }
108
109        let mut handler = CustomHandler::new();
110
111        handler.ev_start(&dyn_any_placeholder());
112        handler.ev_start(&dyn_any_placeholder());
113        handler.ev_close(&dyn_any_placeholder(), false);
114
115        assert_eq!(handler.start_count, 2, "ev_start should be called twice");
116        assert_eq!(handler.close_count, 1, "ev_close should be called once");
117    }
118
119    /// Test that the trait is object-safe and can be used as Box<dyn EventHandler>
120    ///
121    /// This test verifies that EventHandler is object-safe by:
122    /// 1. Creating Box<dyn EventHandler> from a concrete type
123    /// 2. Calling methods through the trait object
124    /// 3. Storing multiple handlers in a Vec<dyn EventHandler>
125    #[test]
126    fn test_object_safety() {
127        struct Handler1 {
128            pub count: usize,
129        }
130
131        impl EventHandler for Handler1 {
132            fn ev_start(&mut self, _worker: &dyn Any) {
133                self.count += 1;
134            }
135        }
136
137        struct Handler2 {
138            pub messages: Vec<String>,
139        }
140
141        impl EventHandler for Handler2 {
142            fn ev_read(&mut self, _worker: &dyn Any, node: &str, sname: &str, msg: &str) {
143                self.messages.push(format!("{}:{}:{}", node, sname, msg));
144            }
145        }
146
147        // This demonstrates object safety - we can store different handler types
148        // in a Vec of trait objects
149        let mut handlers: Vec<Box<dyn EventHandler>> = Vec::new();
150        handlers.push(Box::new(Handler1 { count: 0 }));
151        handlers.push(Box::new(Handler2 {
152            messages: Vec::new(),
153        }));
154
155        // Call ev_start on all handlers
156        for handler in &mut handlers {
157            handler.ev_start(&dyn_any_placeholder());
158        }
159
160        // Call ev_read on all handlers
161        for handler in &mut handlers {
162            handler.ev_read(&dyn_any_placeholder(), "node1", "stdout", "test");
163        }
164
165        // The fact that we can compile and run this code proves that
166        // EventHandler is object-safe. The trait object can be used
167        // polymorphically.
168        assert!(
169            true,
170            "Object safety test passed - Box<dyn EventHandler> works"
171        );
172    }
173
174    /// Helper to create a placeholder for dyn Any
175    fn dyn_any_placeholder() -> Box<dyn Any> {
176        Box::new(())
177    }
178
179    /// Test that EventHandler is Send and Sync (required for Box<dyn EventHandler>)
180    #[test]
181    fn test_send_sync() {
182        struct SendSyncHandler;
183
184        impl EventHandler for SendSyncHandler {}
185
186        fn assert_send<T: Send>() {}
187        fn assert_sync<T: Sync>() {}
188
189        assert_send::<Box<dyn EventHandler>>();
190        assert_sync::<Box<dyn EventHandler>>();
191        assert_send::<SendSyncHandler>();
192        assert_sync::<SendSyncHandler>();
193    }
194}