Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling connection failures with IO::Socket::Async

I'm working on a small project using IO::Socket::Async. I'm trying write some tests to make sure I'm handling a connection loss properly but my initial attempts didn't go as planned. I thought using a QUIT phaser would work but that didn't give any response in the tests I tried closing the supply but that isn't giving the results I was hoping for. Can someone point me in the right direction on how to handle a connection loss with IO::Socket::Async?

An example of the supply where I try to use the quit is below. Since it isn't working how I expected. I am not sure if I am going about this correctly.

supply whenever $connection -> $event {
    if $event ~~ /event message/ {
       emit { status => $event };
    }
    QUIT {
        .note;
        say 'conection lost';
    }
}
like image 491
Amuro Ray Avatar asked Oct 29 '18 22:10

Amuro Ray


1 Answers

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.

like image 77
Jonathan Worthington Avatar answered Sep 27 '22 16:09

Jonathan Worthington