Yesterday I learned a few things about signals in Deno and how to use them to gracefully terminate a (sub-)subprocess including a running Oak server
Don't panic if your signal panics
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "Refusing to register signal 9" }', runtime/ops/signal.rs:185:67
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
That's what I got trying to listen to SIGKILL
, though thanks to this comment I learned that SIGKILL
, SIGSTOP
, SIGILL
, SIGFPE
, and SIGSEGV
cannot be registered, as per Rust docs, which is of interest, because Deno runs on Rust ๐
Fortunately there's more signals we can choose from and in my case I'm using SIGQUIT
which also sounds much friendlier ๐ฅฐ
Let's get to the actual code
So I changed the listening part of my Oak server to
const controller = new AbortController();
const sig = Deno.signal("SIGQUIT");
sig.then(controller.abort); // abort the controller when receiving the signal
const { signal } = controller;
export const server = async () => {
await app.listen({ port, hostname, signal });
};
And the shutDown
function which I'm using in my custom CLI to stop after a set duration, to get my break and hold my promises to my partner that I'm ready in 25m ๐
function shutDown(reason?: string | void) {
p.kill("SIGQUIT"); // `.kill()` sends the provided signal to the subprocess
p.close(); // closes the subprocess and frees the memory
console.log(reason ?? red(bold("Gracefully shutting down")));
Deno.exit(); // finally terminates the CLI with everything cleaned up
}
I wrote a much more detailed article about all this on my freshly started blog running on Deno, Oak, SSR, Go & Fly.io
Gracefully close sub-subprocess using signals in Deno ๐ฆ
Many more articles are in the pipeline, so stay tuned ๐ป
Also please let me know if you have any feedback or question, here in the comments or on Twitter @CanRau
Top comments (0)