Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebSockets in Chrome and Firefox Disconnecting After One Minute of Inactivity

Tags:

I have found that WebSockets in Chrome and Firefox disconnect after exactly one minute of inactivity. Based on stuff I've seen online, I was all set to blame proxies or some server settings or something, but this does not happen in IE or Edge. It seems like if sockets are disconnected by the server after one minute of inactivity that would apply to IE and Edge just as much as Chrome and Firefox.

Does anyone know why this is? Is it documented anywhere? I know a possible way to stop it by pinging, but I'm more interested in why it's happening. The reason code given on disconnect is 1006, indicating that the browser closed the connection. No errors are thrown and the onerror event for the socket is not triggered.

This project was built at https://glitch.com/edit/#!/noiseless-helmet where you can see and run everything. The client page is served here: https://noiseless-helmet.glitch.me/

Here is my client page:

<div id="div"> </div> <script>   let socket = new WebSocket("wss://noiseless-helmet.glitch.me/");   socket.onmessage = function(event) {     div.innerHTML += "<br>message " + new Date().toLocaleString() + " " + event.data;   };   socket.onopen = function (event) {     div.innerHTML += "<br>opened " + new Date().toLocaleString();     socket.send("Hey socket! " + new Date().toLocaleString());   };   socket.onclose = function(event) {     div.innerHTML += "<br>socket closed " + new Date().toLocaleString();     div.innerHTML += "<br>code: " + event.code;     div.innerHTML += "<br>reason: " + event.reason;     div.innerHTML += "<br>clean: " + event.wasClean;   };   socket.onerror = function(event) {     div.innerHTML += "<br>error: " + event.error;   }; </script> 

And here is my Node.js server code:

var express = require('express'); var app = express(); app.use(express.static('public'));  let server = require('http').createServer(),   WebSocketServer = require('ws').Server,   wss = new WebSocketServer({ server: server });  app.get("/", function (request, response) {   response.sendFile(__dirname + '/views/index.html'); });  let webSockets = []; wss.on('connection', function connection(socket) {   webSockets.push(socket);   webSockets.forEach((w) => { w.send("A new socket connected"); });   socket.on('close', (code, reason) => {     console.log('closing socket');     console.log(code);     console.log(reason);     let i = webSockets.indexOf(socket);     webSockets.splice(i, 1);   }); });  server.on('request', app); server.listen(process.env.PORT, function () {   console.log('Your app is listening on port ' + server.address().port); }); 
like image 663
user12861 Avatar asked Mar 21 '18 13:03

user12861


People also ask

Why does my WebSocket disconnect?

WebSocket disconnects can happen by choice, or due to exceptional/error conditions. Here is some information about what happens in each case: Clean disconnect: During a clean disconnect, the user or application will initiate a disconnect sequence.

How do I change web transport inactive timeout?

change the web-transport inactive-timeout in the client profile to more than 60 seconds. To disable the Chrome feature, key in "chrome://flags" in Chrome URL field, search for "Throttle Javascript timer" and disable the feature.

How do you keep WebSockets alive?

The basic idea is to enable a bi-directional communcation between client and server, without the need to oepning multiple http connections (e.g., long polling). The Websocket only defines the protocol on the wire and allow you to choose the application level protocol by Sec-WebSocket-Protocol .

Do WebSockets time out?

A WebSocket times out if no read or write activity occurs and no Ping messages are received within the configured timeout period. The container enforces a 30-second timeout period as the default. If the timeout period is set to -1 , no timeout period is set for the connection.


2 Answers

As much as i understood from researching this, this is caused by websocket timing out over a period of time when no data is sent. This is probably per browser.

You could use pings to resolve this or just reconnect when you need to use the socket again.

It makes sense to not keep sockets open when they are not used from server side as from browser side. For example, Chrome has a limit how many connections can be open, if the limit would be 64 connections and you have open 64 tabs (which is very likely for me as i always have loads of tabs open) and each tab is connected to a server, no more connections could be done (Actually similar thing happened to me once, when i ran out of available sockets in Chrome, funny).

There is proxy_read_timeout (http://nginx.org/r/proxy_read_timeout) which as well applies to WebSocket connections. You have to bump it if your backend do not send anything for a long time. Alternatively, you may configure your backend to send websocket ping frames periodically to reset the timeout (and check if the connection is still alive).

https://forum.nginx.org/read.php?2,236382,236383#msg-236383

Web Sockets have an idle timeout of 60 seconds: if you do not use a heartbeat or similar via ping and pong frames then the socket assumes that the user has closed the page and closes the socket to save resources.

https://www.codeproject.com/Questions/1205863/Websocket-is-closed-after-min

https://github.com/tornadoweb/tornado/issues/1070

like image 43
Hendry Avatar answered Oct 30 '22 21:10

Hendry


It seems like if sockets are disconnected by the server after one minute of inactivity that would apply to IE and Edge just as much as Chrome and Firefox.

Hmmm, no, it doesn't. IE and Edge might be implementing a ping packet as part of the WebSocket protocol.

The WebSocket protocol includes support for a protocol level ping that the JavaScript API doesn't expose. It's a bit lower-level than the user level pinging that is often implemented.

This ping-pong traffic resets the timers in any network intermediaries (proxies, load balancers, etc') - and they all time connections to mark stale connections for closure (for example, the Heroku setup times connections at 55 seconds).

Most browsers trust the server to implement the ping, which is polite (since servers need to manage their load and their timeout for pinging...

...however it's also slightly frustrating, since browsers have no idea if a connection was abnormally lost and JavaScript doesn't emit an event for the WebSocket protocol ping. This is why many JavaScript clients implement a user level ping (i.e., a JSON {event: "ping", data: {...}} or another "empty" event message).

Anyway, I just wanted to point out that your assumption was incorrect, this is still a timeout occurring and the difference in browser behavior is probably related to the browsers themselves.

For a few specifics regarding nginx default timeouts (when proxying WebSocket connections) you can read @Hendry's answer.

like image 50
Myst Avatar answered Oct 30 '22 22:10

Myst