My Solution to Deno Watch Mode Signal Handling
Source: Dev.to
To fix the Deno watch mode issue, I researched both Deno and Node.js. I want to use Node.js's approach but implement it in Rust for Deno. Rust doesn't have a built-in process.kill() function like JavaScript to send signals, but we can simulate this using channels. When creating a channel, we get a sender (Tx) and a receiver (Rx) that work together, which helps avoid race conditions. I created a pull request (PR) that uses a channel to allow the worker process to inform the watcher process when the INT signal is handled, instead of letting the watcher process handle and ignore it. Here’s how I set it up: I also removed the INT handler from the watcher process and replaced it with the channel's receive handler: This approach requires a better understanding of how the signal API is implemented in Deno. The Signal.rs file shows how the Deno.addSignalListener() or process.on(signalName, callback) API works. I'm still looking for the right place to trigger the channel sender without breaking existing behavior. Implementing this feature has been the most challenging task I've faced recently. Three months ago, I had never written a line of Rust, but now I'm working on something significant written in Rust. I can't believe how far I've come since starting my open-source journey. I want to thank my professor, humphd, for encouraging everyone in class to get involved in the open-source community. Everyone has grown so much this semester; this has been the best course I've taken. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
// Create a channel before starting the worker process
let (ctrl_c_tx, mut ctrl_c_rx) = tokio::sync::mpsc::unbounded_channel::<()>(); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Create a channel before starting the worker process
let (ctrl_c_tx, mut ctrl_c_rx) = tokio::sync::mpsc::unbounded_channel::<()>(); CODE_BLOCK:
// Create a channel before starting the worker process
let (ctrl_c_tx, mut ctrl_c_rx) = tokio::sync::mpsc::unbounded_channel::<()>(); CODE_BLOCK:
let watcher_communicator = Arc::new(WatcherCommunicator::new(WatcherCommunicatorOptions { // Pass the sender to the worker ctrl_c_tx: ctrl_c_tx.clone(), })); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
let watcher_communicator = Arc::new(WatcherCommunicator::new(WatcherCommunicatorOptions { // Pass the sender to the worker ctrl_c_tx: ctrl_c_tx.clone(), })); CODE_BLOCK:
let watcher_communicator = Arc::new(WatcherCommunicator::new(WatcherCommunicatorOptions { // Pass the sender to the worker ctrl_c_tx: ctrl_c_tx.clone(), })); COMMAND_BLOCK:
impl WatcherCommunicator { // Public function to inform the watcher process pub fn handle_ctrl_c(&self) -> Result<(), SendError<()>> { self.ctrl_c_tx.send(()) }
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
impl WatcherCommunicator { // Public function to inform the watcher process pub fn handle_ctrl_c(&self) -> Result<(), SendError<()>> { self.ctrl_c_tx.send(()) }
} COMMAND_BLOCK:
impl WatcherCommunicator { // Public function to inform the watcher process pub fn handle_ctrl_c(&self) -> Result<(), SendError<()>> { self.ctrl_c_tx.send(()) }
} COMMAND_BLOCK:
// _ = deno_signals::ctrl_c() => { _ = ctrl_c_rx.recv() => { Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// _ = deno_signals::ctrl_c() => { _ = ctrl_c_rx.recv() => { COMMAND_BLOCK:
// _ = deno_signals::ctrl_c() => { _ = ctrl_c_rx.recv() => {