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)