hyper
hyper copied to clipboard
Implement a way to tell if the remote connection was closed
It would be very helpful if I was able to tell that the remote server closed the connection.
From my conversation with @Lukasa, he said it "...Should be possible for the code to work out if the conn was closed ‘cleanly’ (I.e. with no outstanding work)"
For background:
When I use Hyper to connect to Apple's Push Notifications Servers, they require a persistent connection to be kept with their servers, but they can close the connection at any time. My implementation would be simplified if I had a way to determine that they had closed the connection before attempting to send a notification. (I'd still have to catch exceptions, but I could cleanly attempt a reconnection before trying to send a notification, as most disconnections are due to idle timeout)
So, here's my thoughts on this.
The easiest way for us to be able to do this is to enhance the BufferedSocket implementation with a fill_nowait method, that avoids blocking by only making a recv_into call if the socket is readable. That can then spot connection termination and also look for control frames like GOAWAY that good implementations will issue before connection termination.
We could then call that method before any method that sends data. We could then spot connection termination and check whether or not the connection is in a relatively clean state (no streams outstanding), and then take advantage of that to cleanly reconnect and do other nice things.
This is trivial in the single-threaded case, but in the multi-threaded case everything gets worse. This is because reading from that socket needs to become serialized, and we don't necessarily want to block any data sending method behind a socket read.
@tbetbetbe do you have suggestions for how to deal with that?
- I like the idea of the fill_nowait method
- for simplicity, it's best if all behaviour that needs synchronization happens in one place so I think the detection of the go-away frame should happen in connection.py
- For multithreading, I think we can still call the fill_nowait method before sending, but wherever we do, we should make sure the caller owns the connection-wide lock.
This is because reading from that socket needs to become serialized, and we don't necessarily want to block any data sending method behind a socket read.
- is this really a problem ? We already serialize access by requiring any reader/writer to acquire the connection object before acting. As long as we kept the goaway detection logic within the existing synchronized sections, the synchronization cost should be no worse in the cases where there is no goaway frame.
is this really a problem ? We already serialize access by requiring any reader/writer to acquire the connection object before acting. As long as we kept the goaway detection logic within the existing synchronized sections, the synchronization cost should be no worse in the cases where there is no goaway frame.
Heh, I think that's what I'm asking you. You've been using the project multithreaded in anger, so you've got a much better feel for what it seems like.
If you're optimistic that it won't hurt, then I'm happy to prototype this and you can play around with it in the multithreaded case and see if it hurts too much.