There are two ways a connection might be terminated:
- EOF, which we consider an "orderly" close. The
whenever
subscription is much like a loop, and the LAST
phaser triggers on orderly end of the stream. So, to handle this case, use LAST
.
- Erroneous termination, such as connection reset by peer, which will trigger the
QUIT
as you wrote (though you need QUIT { default { note $_ } }
to actually handle it, just as with CATCH
).
It seems that quite a few more cases are considered "orderly" (that is, the EOF case) than at least I expected. For example, run a server like this:
react {
whenever IO::Socket::Async.listen('localhost', 4242) -> $conn {
whenever $conn -> $stuff {
$conn.print($stuff);
}
}
}
And a client like this:
my $conn = await IO::Socket::Async.connect('localhost', 4242);
react {
whenever $conn -> $stuff {
say "Got back $stuff";
LAST {
say "Connection closed";
done;
}
QUIT {
default {
say "Connection lost: $_";
done;
}
}
}
whenever Supply.interval(1) {
$conn.print("hello $_\n");
}
}
Then Ctrl+C the server, and - at least on my local setup (Ubuntu in a VM) - it triggered the LAST
. I wondered if this could be some kind of bug, so traced it all the way back into the VM's I/O binding, and no, we really are getting EOF passed to us from the operating system in that case, not an error. Sticking the server on a separate machine, and then disconnecting the wifi on my local one, was enough to trigger the QUIT
case with a "Connection reset by peer".
In summary, QUIT
is the right way to handle erroneous loss of connection, but LAST
is triggered by EOF, and that shows up in some cases that we might consider "connection loss"; only the protocol being spoken atop of the socket can really determine whether this was an unexpected time for things to come to an end.