I have a small program which runs until a SIGINT is received or two lines (press enter twice) from stdin are received. The react block logic is:
react {
whenever signal(SIGINT) {
say "Got signal";
exit;
}
whenever $*IN.lines.Supply {
say "Got line";
exit if $++ == 1 ;
}
}
Program will exit on two entered lines as expected.
However CTRL-C will not do anything, unless it is followed by a line (enter).
If I switch the order of the whenever blocks, the program is interrupted by a SIGINT but doesn't execute the signal whenever block
react {
whenever $*IN.lines.Supply {
say "Got line";
exit if $++ == 1 ;
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
Is there some other setup required before using the signal sub? Is the order of whenever blocks important in a react block?
Update
So it seems the lines() call is blocking the react block from executing (thanks @Håkon). I kind of get it.
When comparing to a similar code structure for reading a socket I'm confused though. The presence of data (or lack of) has no effect on the signal handler executing and it can read lines just fine in this example:
my $listener=IO::Socket::Async.listen("0.0.0.0",4432);
react {
whenever $listener {
whenever $_.Supply.lines() {
say "Got line";
}
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
#testing with:
# curl http://localhost:4432
Why does this behave so different to my original code?
If we have multiple instances of useEffect in the component, all the useEffect functions will be executed in the same order as they are defined inside the component.
Only Call Hooks at the Top Level Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders.
What is a dependency array. Dependency arrays are a concept that is tightly coupled to hooks in React (thus also to function components). Some hooks, like useEffect and useCallback have 2 arguments. The first one is a callback (a function), and the second one is the dependency array.
log("USE LAYOUT EFFECT FUNCTION TRIGGERED"); }); Even though the useLayoutEffect Hook is placed after the useEffect Hook, the useLayoutEffect Hook is triggered first!
The order doesn't matter provided the data sources really behave in an asynchronous manner, which unfortunately is not the case here. The Supply
coercer on a Seq
does not introduce any concurrency, and does immediately try to produce a value to emit on the Supply
, which in turn blocks on reading from $*IN
. Thus, the second subscription doesn't have chance to be set up; the same underlying issue causes the other problems observed.
The solution is to force the reading to happen "elsewhere". We can do that with Supply.from-list(...)
, plus telling it we really do want to use the current scheduler rather than its default CurrentThreadScheduler
. Thus, this behaves as wanted:
react {
whenever Supply.from-list($*IN.lines, scheduler => $*SCHEDULER) {
say "Got line";
exit if $++ == 1 ;
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
It's likely this area will be revised somewhat in future Perl 6 versions. The current behavior was well-intended; the design principle was to avoid implicit introduction of concurrency, following the general principle that supplies are a tool for managing concurrency that inherently exists, rather than for introducing it. However, in reality, the lack of concurrency here has probably tripped up more folks than it has helped. (Further, we may look into offering real non-blocking file I/O, rather than building it from sync file I/O + threads.)
Here is a variant that runs the signal handler (based on this answer), but unfortunately autoflushing of $*IN
seems to be turned off:
my $lines = supply {
whenever start $*IN.lines.Supply {
whenever .lines { .emit }
}
}.Channel;
react {
whenever signal(SIGINT) {
say "Got signal";
exit;
}
whenever $lines {
say "Got line: '{$_}'";
exit if $++ == 1;
}
}
Now you have to press CTRL-D
to print the lines, and then it print all lines entered as a concatenated string and after that $*IN
is closed.. How can I turn on autoflushing for $*IN
in this case?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With