Skip to main content

ek_event/
engine.rs

1//! `EventEngine`:无界队列 + 单分发线程 + 定时线程。
2//!
3//! 线程模型(对齐 enkeep_trade 的实际用法:各组件跨线程共享同一引擎):
4//! - **`EventEngine` 满足 `Send + Sync`**:可经 `Arc<EventEngine>` 供任意多线程共享,
5//!   `put / register / unregister / register_general / unregister_general / is_active /
6//!   pending_events / start / stop` 全部可从任意线程调用
7//! - 分发端保持**单线程串行**(对齐原版):同一 type 的事件按 put 顺序送达,
8//!   同 type 的 handler 按注册顺序执行,general handler 随后
9//! - handler 内部若需并行,由 handler 自行分流(引擎不替业务并行)—— 与原版一致
10//!
11//! 生命周期与原版对齐:
12//! - `start()` 幂等;分发线程 `recv_timeout(1s)` 轮询 `active`,
13//!   对齐原版 `_run` 的 `get(block=True, timeout=1)`
14//! - `put()` 在 start **之前**投递合法(事件入队,随 start 分发,对齐原版 `Queue.put`)
15//! - `stop()` 置 inactive 后 join 两线程;**队列残余事件被丢弃**(对齐原版),
16//!   并把 `pending` 计数清零;stop 后引擎不可重启(receiver 已被消费,与原版线程死透一致)
17//! - 使用方如需"等排空":所有 put 完成后轮询 [`EventEngine::pending_events`] 归零再 stop
18//!
19//! handler panic 被 catch_unwind 隔离(修正项,见 DESIGN.md §2)。
20//!
21//! 队列实现:crossbeam-channel `unbounded()`
22//! - 对应原版 Python `queue.Queue()` 无界语义
23//! - MPMC 无锁快路径(单字 CAS),百万级事件/秒热路径开销低
24//! - Sender/Receiver 均可克隆 → 后续把 tick 等热点事件分流到独立 worker 时无需换型
25//! - `send` 在无任何 Receiver 时报 `SendError` → 映射 [`PutError::Stopped`]
26
27use crate::event::Event;
28use crate::handler::{HandlerFn, HandlerId, HandlerRegistry};
29use crossbeam_channel::{Receiver, RecvTimeoutError, SendError, Sender};
30use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
31use std::sync::{Arc, Mutex, RwLock};
32use std::time::Duration;
33
34/// put 失败原因(已 stop 或分发线程已退出)。
35/// 注意:start **之前** put 是合法的(事件入队,随 start 分发,对齐原版)。
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum PutError {
38    /// 事件未入队。
39    Stopped,
40}
41
42/// 事件引擎。**Send + Sync**:可被 `Arc` 共享于多线程。
43pub struct EventEngine {
44    /// 定时间隔(默认 1s)。构造后不变,无需锁。
45    interval: Duration,
46    /// 队列发送端;`stop()` 写 None 断开,加速分发线程退出。
47    /// `RwLock` 承担就地可变 + 让引擎满足 Sync(“crossbeam Sender 本身 Sync,锁只为 stop 能写”)。
48    sender: RwLock<Option<Sender<Event>>>,
49    /// 队列接收端,start 时 take 交给分发线程。
50    /// crossbeam `Receiver` 是 Send 非 Sync,Mutex 包一层即取 Sync(Option<Receiver>: Send)。
51    receiver: Mutex<Option<Receiver<Event>>>,
52    /// handler 注册表(线程安全,自带 RwLock)。
53    handlers: Arc<HandlerRegistry>,
54    /// 引擎存活标志。
55    active: Arc<AtomicBool>,
56    /// 分发线程句柄(stop 时取出 join)。
57    worker: Mutex<Option<std::thread::JoinHandle<()>>>,
58    /// 定时线程句柄(stop 时取出 join)。
59    timer: Mutex<Option<std::thread::JoinHandle<()>>>,
60    /// 已入队未分发完的事件计数(近似值,供等排空;stop 后强制清零)。
61    pending: Arc<AtomicU64>,
62}
63
64impl Default for EventEngine {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl EventEngine {
71    /// 新引擎,默认定时间隔 1s(对齐原版 `interval: int = 1`)。
72    pub fn new() -> Self {
73        Self::with_interval(Duration::from_secs(1))
74    }
75
76    /// 自定义定时间隔。
77    pub fn with_interval(interval: Duration) -> Self {
78        let (tx, rx) = crossbeam_channel::unbounded();
79        Self {
80            interval,
81            sender: RwLock::new(Some(tx)),
82            receiver: Mutex::new(Some(rx)),
83            handlers: Arc::default(),
84            active: Arc::new(AtomicBool::new(false)),
85            worker: Mutex::new(None),
86            timer: Mutex::new(None),
87            pending: Arc::new(AtomicU64::new(0)),
88        }
89    }
90
91    /// 启动分发线程与定时线程;已启动 / 已 stop 时为空操作(幂等)。
92    /// 可从任意线程调用。
93    pub fn start(&self) {
94        // 先抢 receiver:双 start 并发时只有一方拿得到,天然去重;
95        // 抢不到(未启动/已 stop)直接返回,避免把 active 置回 true 造成假活。
96        let Some(rx) = self.receiver.lock().unwrap().take() else {
97            return;
98        };
99        self.active.store(true, Ordering::SeqCst);
100
101        let worker = std::thread::Builder::new()
102            .name("ek-event-dispatch".into())
103            .spawn({
104                let handlers = self.handlers.clone();
105                let active = self.active.clone();
106                let pending = self.pending.clone();
107                move || run_dispatch(rx, handlers, active, pending)
108            })
109            .expect("spawn dispatch thread");
110
111        let timer = std::thread::Builder::new()
112            .name("ek-event-timer".into())
113            .spawn({
114                let sender = self.sender.read().unwrap().clone();
115                let active = self.active.clone();
116                let step = self.interval;
117                let pending = self.pending.clone();
118                move || run_timer(sender, active, step, pending)
119            })
120            .expect("spawn timer thread");
121
122        *self.worker.lock().unwrap() = Some(worker);
123        *self.timer.lock().unwrap() = Some(timer);
124    }
125
126    /// 投递事件。start 前投递合法(事件入队,start 后分发,对齐原版);
127    /// 已 stop / 通道断开时返回 [`PutError::Stopped`]。
128    pub fn put(&self, event: Event) -> Result<(), PutError> {
129        self.pending.fetch_add(1, Ordering::AcqRel);
130        let sent = match self.sender.read().unwrap().as_ref() {
131            Some(tx) => tx.send(event),
132            None => {
133                self.pending.fetch_sub(1, Ordering::AcqRel);
134                return Err(PutError::Stopped);
135            }
136        };
137        match sent {
138            Ok(()) => Ok(()),
139            Err(SendError(_)) => {
140                self.pending.fetch_sub(1, Ordering::AcqRel);
141                Err(PutError::Stopped)
142            }
143        }
144    }
145
146    /// 注册 event_type 精确 handler,返回 [`HandlerId`] 供注销。
147    /// event_type 接受 `&str` / `String` / `format!(...)` 结果(对齐原版 str 语义)。
148    pub fn register(&self, event_type: impl Into<String>, f: HandlerFn) -> HandlerId {
149        self.handlers.register(event_type, f)
150    }
151
152    /// 注销任意位置的 handler;true 表示确实注销了某个。
153    pub fn unregister(&self, id: HandlerId) -> bool {
154        self.handlers.unregister(id)
155    }
156
157    /// 注册通用 handler(收所有事件)。
158    pub fn register_general(&self, f: HandlerFn) -> HandlerId {
159        self.handlers.register_general(f)
160    }
161
162    /// 注销通用 handler。
163    pub fn unregister_general(&self, id: HandlerId) -> bool {
164        self.handlers.unregister_general(id)
165    }
166
167    /// 引擎是否在运行。
168    pub fn is_active(&self) -> bool {
169        self.active.load(Ordering::SeqCst)
170    }
171
172    /// 已入队、尚未分发完的事件数(近似)。
173    /// 使用方在 stop 前想要"等排空",轮询此处归零即可;
174    /// stop 会强制清零(残余事件按"丢弃"语义不再计数)。
175    pub fn pending_events(&self) -> u64 {
176        self.pending.load(Ordering::SeqCst)
177    }
178
179    /// 停止引擎并 join 两线程;幂等,可从任意线程调用。
180    /// 队列残余事件被丢弃(对齐原版);stop 后引擎不可重启。
181    pub fn stop(&self) {
182        if !self.active.swap(false, Ordering::SeqCst) {
183            return; // 已停,幂等
184        }
185        // 丢弃发送端:put 从此报 Stopped;定时端的 send 也会失败而退出
186        *self.sender.write().unwrap() = None;
187        // 先取句柄再 join(join 期间不持有锁)
188        let timer_handle = self.timer.lock().unwrap().take();
189        if let Some(t) = timer_handle {
190            let _ = t.join();
191        }
192        let worker_handle = self.worker.lock().unwrap().take();
193        if let Some(w) = worker_handle {
194            let _ = w.join();
195        }
196        // 残余事件按"丢弃"语义不再计数,防止调用方误以为还在排空
197        self.pending.store(0, Ordering::SeqCst);
198    }
199}
200
201/// 分发线程主体:对齐原版 `_run` 的 `get(block=True, timeout=1)`。
202fn run_dispatch(
203    rx: Receiver<Event>,
204    handlers: Arc<HandlerRegistry>,
205    active: Arc<AtomicBool>,
206    pending: Arc<AtomicU64>,
207) {
208    const POLL: Duration = Duration::from_secs(1);
209    loop {
210        if !active.load(Ordering::SeqCst) {
211            break;
212        }
213        match rx.recv_timeout(POLL) {
214            Ok(event) => {
215                pending.fetch_sub(1, Ordering::AcqRel);
216                process_event(&event, &handlers);
217            }
218            Err(RecvTimeoutError::Timeout) => continue, // 轮询 active 旗标
219            Err(RecvTimeoutError::Disconnected) => break,
220        }
221    }
222}
223
224/// 定时线程主体:对齐原版 `_run_timer`(sleep(interval) 后投递 TIMER 事件)。
225fn run_timer(
226    sender: Option<Sender<Event>>,
227    active: Arc<AtomicBool>,
228    step: Duration,
229    pending: Arc<AtomicU64>,
230) {
231    let Some(sender) = sender else { return };
232    loop {
233        std::thread::sleep(step);
234        if !active.load(Ordering::SeqCst) {
235            break;
236        }
237        pending.fetch_add(1, Ordering::AcqRel);
238        if sender.send(Event::new(crate::EVENT_TIMER)).is_err() {
239            pending.fetch_sub(1, Ordering::AcqRel);
240            break;
241        }
242    }
243}
244
245/// 分发一个事件:该 type 的 handler 先(注册顺序),general handler 后;
246/// 单个 handler 的 panic 被 catch_unwind 隔离,不影响后续 handler 与事件。
247fn process_event(event: &Event, handlers: &HandlerRegistry) {
248    for f in handlers.snapshot(&event.event_type) {
249        let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(event)));
250    }
251}