Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Reconnection and KeepAlive #767

Closed
theavijitsarkar opened this issue Jun 28, 2016 · 16 comments
Closed

Reconnection and KeepAlive #767

theavijitsarkar opened this issue Jun 28, 2016 · 16 comments

Comments

@theavijitsarkar
Copy link

theavijitsarkar commented Jun 28, 2016

My end requirement is to be connected. So if i get disconnected, I must connect back.

To do this the biggest challenge I am facing is that neither the close event is called, not are my sends failing, neither is ping pong throwing error.

I added a ping pong in the background to keepAlive the connection.

ws.ping(null,null,false)

However that didnt also report close events. As that itself stopped responding when I pulled off the internet from the router.

My end goal is to remain connected. Please suggest how to do that

@theavijitsarkar
Copy link
Author

Do note, I have tried

@humingchun #459

ws._socket.setKeepAlive(true,100)

Also, one fork by @FlorianBELLAZOUZ
https://github.com/FlorianBELLAZOUZ/ws

@john-doherty
Copy link

Are there any plans to add a keepAlive feature ? The reason I ask is almost everyone using this lib must be implementing their own workaround.

@lpinca
Copy link
Member

lpinca commented Jan 25, 2017

@john-doherty yeah an heartbeat system based on server sent pings makes sense. Not before 2.0.0 is released though.

@gearintellix
Copy link

anyone can tell me how to reconnect this socket?

i try using like w3c socket,

var ws=require("ws");
var wsx;

var init=function() {
   wsx=new ws("ws://example.com");
   wsx.on("close",function() {
      console.log("try to reconnect");
      init();
   };
}
init();

but it not worked, no callback after reconnect

@PArns
Copy link

PArns commented Mar 6, 2017

I've the exact same problem! I had to implement my own reconnect handling but more the WebSocket doesn't recognize a connection termination which is not caused by the server (client connection/internet issues). This is really a big problem here :(

You can easily debug/test that by connecting to a WS Server and then pulling the LAN cable

@mitchcapper
Copy link

First you could use ping/pong and if no pong is returned within X time assume it failed no? Also I find on connection issues (with ping/pong) the ready state of the socket will change so reconnecting then. it would be nice if there was a reconnect or "open" call rather than having to create a new web socket (but fairly minor).

@lpinca
Copy link
Member

lpinca commented May 12, 2017

As @michaelsanford said you can use something like this: https://github.com/websockets/ws#how-to-detect-and-close-broken-connections.

Reconnection can be handled with one of the many modules available for this on npm.

Closing, feel free to continue discussing on the closed thread.

@aleqx
Copy link

aleqx commented Feb 14, 2019

Sorry for necro. Do i take it that there is still no auto-reconnect feature, @lpinca ? The link you usggested above is when you implement both client and server. I connect to a public wss:// server which doesn't know ping/pong'ing. I just want to continuously try to reconnect when the connection drops, regardless of why it dropped.

I look for a simple but reliable wrapper code to implement reconnection but didn't find much. I implemented my own, with timeout too, inspired from https://github.com/joewalnes/reconnecting-websocket/blob/master/reconnecting-websocket.js, and I'm leaving it below - please do feel free to point out if it can be made more reliable.

var timeout = 10; // seconds

function connect(address, protocols, options) {
    let ws = new WebSocket(address, protocols, options);
    let timerTimeout = setTimeout(() => ws.terminate(), timeout * 1000); // force close unless cleared on 'open'
    ws.on('open', () => {
        console.log('Opened. Clearing timeout ...');
        clearTimeout(timerTimeout);
        // do your thing here, like ws.send(...);
    });
    ws.on('message', data => console.log(data.slice(0, 76)+' ...'));
    ws.on('close', () => {
        clearTimeout(timerTimeout);
        console.error('Websocket connection closed. Reconnecting in %f seconds ...', timeout);
        setTimeout(() => connect(address, protocols, options), timeout * 1000);
    });
    ws.on('error', reason => console.error('Websocket error: ' + reason.toString()));
    return ws;
}

Note to self: error is not emitted if ws.terminate() is called, but close is.

@lpinca
Copy link
Member

lpinca commented Feb 14, 2019

That's correct, there is no auto reconnect.

@royalpinto
Copy link

@lpinca Any chances of this auto-reconnect feature getting implemented?

@nolimitdev
Copy link

@aleqx @royalpinto to fire onclose event on client side when its connection is broken (e.g. tested with unplugging LAN cable or router restart) you can implement heartbeat mechanism recommended by @lpinca: https://github.com/websockets/ws#how-to-detect-and-close-broken-connections. But it is depends on pings from server. If you can not modify target server to send pings to clients you can send ping from your client to server and you do not need to listen for ping (maybe server do not support ping/pong) because sending ping (or any data) causes that ws client notices broken connection and fires onclose event. In onclose you should already have implemented own reconnect mechanism. Note that broken connection is not noticed immediately after ws.ping() or ws.send() but it takes some time (e.g. in my case on windows I was sending ping each 5 seconds and after LAN cable unplugging "onclose" was fired after 3rd ping (in about 15 seconds). On raspberian (maybe any Unix?) I notices that onclose is fired after unplugging + plugging again but it also acceptable because reconnection happens on connection restored.

Auto reconnect depends on many variables and differs from use-case to use-case so it should be tailored by your needs.

@david9991
Copy link

Actually the WebSocket connection is closed by underlying HTTP session if you are using Nginx or some other reverse proxy. WebSocket traffic and keep-alive(ping/pong) won't affect underlying HTTP (reverse proxy) anymore after your protocol upgraded to WebSocket, so HTTP connection will timeout eventually due to no any HTTP traffic.
You can add

proxy_read_timeout 30d;
proxy_send_timeout 30d;

to your Nginx location directive, and you can keep the underlying HTTP and WebSocket alive for 30 days.

@david9991
Copy link

Unfortunately, I am using Cloudflare, and can't keep underlying HTTP alive, it'll timeout every 100 seconds. So an API which can interactive with underlying HTTP connection may help...

@adrian-gierakowski
Copy link

Sorry for necro. Do i take it that there is still no auto-reconnect feature, @lpinca ? The link you usggested above is when you implement both client and server. I connect to a public wss:// server which doesn't know ping/pong'ing. I just want to continuously try to reconnect when the connection drops, regardless of why it dropped.

I look for a simple but reliable wrapper code to implement reconnection but didn't find much. I implemented my own, with timeout too, inspired from https://github.com/joewalnes/reconnecting-websocket/blob/master/reconnecting-websocket.js, and I'm leaving it below - please do feel free to point out if it can be made more reliable.

var timeout = 10; // seconds

function connect(address, protocols, options) {
    let ws = new WebSocket(address, protocols, options);
    let timerTimeout = setTimeout(() => ws.terminate(), timeout * 1000); // force close unless cleared on 'open'
    ws.on('open', () => {
        console.log('Opened. Clearing timeout ...');
        clearTimeout(timerTimeout);
        // do your thing here, like ws.send(...);
    });
    ws.on('message', data => console.log(data.slice(0, 76)+' ...'));
    ws.on('close', () => {
        clearTimeout(timerTimeout);
        console.error('Websocket connection closed. Reconnecting in %f seconds ...', timeout);
        setTimeout(() => connect(address, protocols, options), timeout * 1000);
    });
    ws.on('error', reason => console.error('Websocket error: ' + reason.toString()));
    return ws;
}

Note to self: error is not emitted if ws.terminate() is called, but close is.

@aleqx
Are you sure this works? The connect in on('close') creates a new ws but the caller of the original invocation to connect will be holding the old, closed socket.

@nolimitdev
Copy link

@adrian-gierakowski you are right, quoted reconnect implementation is wrong. It says that it is inspired by https://github.com/joewalnes/reconnecting-websocket/blob/master/reconnecting-websocket.js but that implementation is OK because each (re)connection is always stored in ReconnectingWebSocket.ws. Quoted implementation could be fixed this way... change connect() to void - so remove return statement and add argument where to store ws... e.g.: connect(address, protocols, options, wsReference) and call main connect() and also connect() in onclose event with that new argument. Sending messages via wsReference.send() will use current connection. But it is also important to handle send() becase it behaves different in different connection states. Once you need handle callback and once try/catch because it can throw.

@nolimitdev
Copy link

I still think that reconnect mechanism should not be part of library but it could be fine @lpinca to add to doc some professional/good practice reconnect example such as we have example for heartbeat mechanism for detecting zombie connections.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests