ninenines / gun

HTTP/1.1, HTTP/2, Websocket client (and more) for Erlang/OTP.
ISC License
891 stars 232 forks source link

Handle websocket with client-side connection issues #231

Closed sezaru closed 4 years ago

sezaru commented 4 years ago

Hello,

Sorry if this is a dumb question, but what is the best way to handle client-side connection issues with a gun websocket.

For example, let's say that I lost internet connection, in this case, I expect that gun would realize after some time that it lost connection to the websocket server and send me a gun_down message.

But for some reason, I receive nothing and when I restore my internet it simply recovers the connection. Now, this is very cool, but I'm not sure about the guarantees of this and what is really happening behind the curtains, is gun simply trying to reconnect automatically for me when the internet connection resumed? Or is this something that the websocket protocol supports and it will simply resume the connection when the internet is back?

The reason I'm asking this is that I receive sequence data from the websocket server, so if my last data has id 10, the next one needs to have id 11. So my fear is that when gun restores automatically my websocket connection, I will not receive 11, but some other newer id.

For now, the way I'm "handling" this is by setting ws_opts with silence_pings set to false and setting a timer that will be reset each time I get a pong message from the server. If that timer triggers, it will force the disconnection.

So, is my solution the right/best one? Or does gun/websocket protocol guarantees that I will always receive the full missing data from the last one I got until the current time when some kind of connectivity issue like internet outage happens?

Thanks!

essen commented 4 years ago

The reconnect is just the retry feature, and while it reconnects it doesn't setup Websocket again automatically. It sends a gun_down message first, then gun_up at which point you have to setup Websocket again.

The disconnect might not be detected immediately, see the TCP half-open problem.

sezaru commented 4 years ago

I see, in this case, can I disable the functionality by using retry: 0 into my connect_opts? That way I will only receive the gun_down message, not the gun_up right?

The disconnect might not be detected immediately, see the TCP half-open problem.

But shouldn't the keepalive handle that? If I got it right, gun will send a ping request after keepalive specified time, shouldn't it recognize the connection as broken, and return a gun_down if it didn't get the pong response?

In my tests, it doesn't matter how much time I let my internet down and how much messages I try to send, I will only get a gun_down message after I restore my internet. Edit: Actually I was able to trigger gun_down without restoring the internet, it takes a while but it does happen eventually.

I guess the best approach is to handle that manually by a timer as shown in the first post.

essen commented 4 years ago

Yes retry => 0 disables it.

The keepalive option is only about sending a PING once in a while. There is currently no timeout for checking whether an ack was received. But there probably shouldn't be anyway, we want options similar to Cowboy's idle_timeout, where as long as we received data from the peer we consider the connection to be up. This has not been implemented yet.

The reason you see gun_down eventually is because the disconnect is triggered when the send buffers have filled up.

sezaru commented 4 years ago

Thanks, @essen now it is clearer to me what is happening!

And also thanks for the cowboy idle_timeout tip, I took a look at their code and how they handle idle_timeout.

I will close the issue then.