我对 Deno Watch Mode 信号处理的解决方案

发布: (2025年12月14日 GMT+8 14:13)
3 min read
原文: Dev.to

Source: Dev.to

问题概述

为了解决 Deno watch 模式的 issue,我研究了 Deno 和 Node.js。 我想采用 Node.js 的做法,但在 Deno 中用 Rust 实现。

Rust 没有像 JavaScript 那样的内置 process.kill() 函数来发送信号,但我们可以使用通道来模拟。 创建一个 channel 时,会得到发送端(Tx)和接收端(Rx),它们协同工作,有助于避免竞争条件。

我提交了一个 pull request (PR),使用通道让 worker 进程在处理 INT 信号后通知 watcher 进程,而不是让 watcher 进程自行处理并忽略它。

解决方案

核心思路是将通道发送端传递给 worker 进程,让 worker 在处理 Ctrl+C 后通知 watcher。 watcher 随后监听该通道,而不是直接处理信号。

创建通道

// Create a channel before starting the worker process
let (ctrl_c_tx, mut ctrl_c_rx) = tokio::sync::mpsc::unbounded_channel::();

将发送端传递给 Worker

let watcher_communicator = Arc::new(WatcherCommunicator::new(
    WatcherCommunicatorOptions {
        // Pass the sender to the worker
        ctrl_c_tx: ctrl_c_tx.clone(),
    },
));

Worker 通知 Watcher

impl WatcherCommunicator {
    // Public function to inform the watcher process
    pub fn handle_ctrl_c(&self) -> Result> {
        self.ctrl_c_tx.send(())
    }
}

替换 INT 处理器

// _ = deno_signals::ctrl_c() => {
_ = ctrl_c_rx.recv() => {

实现细节

了解 Deno 中信号 API 的实现方式至关重要。 Signal.rs 文件展示了 Deno.addSignalListener()process.on(signalName, callback) API 的工作原理。 我仍在寻找一个最佳位置来触发通道发送端,以免破坏现有行为。

结论

实现此功能是我近期遇到的最具挑战性的任务。 三个月前,我从未写过一行 Rust,如今已经向 Deno 贡献了大量 Rust 代码。 我非常感谢我的教授 humphd 鼓励班上每个人参与开源社区。 这个学期是一次非凡的学习经历。

Back to Blog

相关文章

阅读更多 »