Let's say I have simple socket listening in one thread and I want to hold another thread until port is opened and socket is actually listening. Which one is correct:
do
? Documentation of do
says The simplest way to run a block
, but body of whenever
is not actually ran until something connects.my $p = Promise.new;
start {
react {
$p.keep: do whenever IO::Socket::Async.listen( "127.0.0.1", 4528 ) -> $c { ... }
}
};
await $p;
whenever
block Supply used in that block got access to scheduler and is already working?my $p = Promise.new;
start {
react {
whenever IO::Socket::Async.listen( "127.0.0.1", 4528 ) -> $c { ... }
$p.keep;
}
};
await $p;
INIT
is a bit unclear. It says it should be ran at runtime ASAP. So it looks like perfect candidate that guarantees block is initialized. But why it does not have access to defined Promise?my $p = Promise.new;
start {
react {
whenever IO::Socket::Async.listen( "127.0.0.1", 4528 ) -> $c {
INIT $p.keep; # ERROR, variable undefined
}
}
};
await $p;
None of the above. :-)
An INIT
block is run immediately after module load, and once in the lifetime of the program. It's typically for doing initialization work related to a module as a whole. So it would run before the start
or react
have even happened.
Option 2 is closer, but not quite there. The Promise
will be kept after the request to start listening has been issued, but that's an asynchronous operation, so there's a race.
Option 1 is wrong, but going in an interesting direction. The whenever
construct establishes a subscription, and evaluates to the Tap
object that represents the subscription. Typically one doesn't care for this object, because the react
/supply
construct does all of the subscription management. However, some kinds of Supply
return more interesting Tap
objects than others. The IO::Async::Socket.listen
method returns an IO::Socket::Async::ListenSocket.
Among the methods on it is socket-port
, which is a Promise
that is kept with the port the server is listening on. The most common use of this is when you request the server listen on whatever port is free and want to discover which port was picked, but you can also use it to find out when the server is certainly listening.
Thus the solution is:
my $p = Promise.new;
start {
react {
my $server = do whenever IO::Socket::Async.listen( "127.0.0.1", 4528 ) -> $c { ... }
whenever $server.socket-port {
$p.keep;
}
}
};
await $p;