Skip to main content

ecat_data/
worker.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2//! 后台任务停机信号:`watch` 通道,发送端可重复触发,接收端可重复等待。
3use tokio::sync::watch;
4
5/// 停机信号接收端;`cancelled()` 可重复调用,已停机时立即返回。
6pub struct Shutdown {
7    rx: watch::Receiver<bool>,
8}
9
10/// 停机信号发送端;`shutdown()` 幂等。
11pub struct ShutdownHandle {
12    tx: watch::Sender<bool>,
13}
14
15impl Shutdown {
16    /// 创建一对信号端;发送端 Drop 也会唤醒等待方(视为停机)。
17    pub fn new() -> (ShutdownHandle, Shutdown) {
18        let (tx, rx) = watch::channel(false);
19        (ShutdownHandle { tx }, Shutdown { rx })
20    }
21
22    /// 等待停机;已停机时立即返回。
23    pub async fn cancelled(&mut self) {
24        if self.is_cancelled() {
25            return;
26        }
27        // 发送端 Drop 时 `changed()` 返回 Err,同样按停机处理,避免永远挂起。
28        let _ = self.rx.changed().await;
29    }
30
31    pub fn is_cancelled(&self) -> bool {
32        *self.rx.borrow()
33    }
34}
35
36impl ShutdownHandle {
37    /// 触发停机;重复调用不 panic。
38    pub fn shutdown(&self) {
39        self.tx.send_replace(true);
40    }
41}
42
43#[cfg(test)]
44mod tests;