I would expect the following code to block until a signal happens - possibly there's something I am missing here.
```javascript:
await Deno.signal(Deno.Signal.SIGINT)
```javascript
const sigs = signal(Deno.Signal.SIGINT);
for await (const _ of sigs) {
break;
}
sigs.dispose();
While I understand the API is unstable, the curious thing is that if I launch processes and hook up readers, the awaiting is honored. If I launch the process with a null stderr, it doesn't - ie:
const srv = await Deno.run({
cmd: [exe, "-c", confFile],
stderr: debug ? "piped" : "null",
stdout: "null",
stdin: "null",
});
possibly there's something I am missing here
Signals currently don't block the event loop from exiting. And I think that's by design, but I don't know.
To work around this, you can, for example, add a setTimeout(() => {}, 9999999). In that case, you'll also want to add a call to Deno.exit or clearTimeout to your handler (if you want to exit based on the signal).
Wouldn't the iterator above block? Also - Deno.signal() on the doc says it is an iterator and promise like...
Signals don't block by design (actually it took a lot of extra effort to make this happen). We haven't actually put a lot of time into this signals API beyond the initial feature patch (hence unstable). It's interesting to hear that you want the default behavior. I feel like there are arguments to be made in either direction...
cc @kt3k
I understand the logic behind not blocking and I agree with it, but I feel like we should provide a way to block that is less hacky than creating a setInterval. Maybe add a .ref method if signals are .unref'd by default, or the other way around if that's what the majority prefers
Similar to https://github.com/denoland/deno/issues/6141
@aricart It blocks the execution of JavaScript below the await expression, but it doesn't block the program from "exiting" (as MarkTiedemann says).
For example, the following doesn't print 123.
await Deno.signal(Deno.Signal.SIGINT);
console.log(123);
We chose this design because if it blocks the exiting from the program, we always need to call .dispose() method of the signal object and that doesn't seem convenient.
For example, a typical use case of signal call would look like the below:
async function handleSignal() {
await Deno.signal(Deno.Signal.SIGINT);
// ... handles sigint and exits ...
}
handleSignal()
someMainFunction();
The above program exits when someMainFunction finishes. If Deno.signal() blocks the program from exiting, the above program doesn't finish because signal handler prevent it from exiting (and that feels unnatural).
The above API then is a bit misleading (something that can be corrected with the doc). If a client wishes to block the exit, it must do that itself, and delegate the signal to resolve the client program exit @kt3k thanks for the clarification.
@aricart I sort of agree that current design is a bit misleading or confusing. My above comment explains how the current design "works", but I personally don't think it's the best among possible solutions. I'm going to create a new issue for it. Thank you for your feedbacks.
I think the main issue is that when getting rid of callbacks creates a different set of usage patterns that have more friction - From the Deno.signal side, it seems very reasonable to await the signal. From the side of std/signal, the iterator of just getting called and handling seems more in line with what you are explaining. Perhaps both types of usages have value.