1

I'm trying to get a persistent connection from my socket.io-client (running on Node.js) to a remote websocket. I do not have control over the remote socket, and sometimes it can go down entirely. I would like to attempt to reconnect() whenever an error or disconnect occurs. In the following example, I'm trying to test the case where the remote host is refusing a connection. In this case, I would like to attempt to reconnect after 1 second. It calls a second time, and exits.

Here's the code:

var events = require('events'),
    util = require('util'),
    io = require('socket.io-client'),
    url = "ws://localhost:12345", // intentionally an unreachable URL
    socketOptions = {
        "transports" : [ "websocket" ],
        "try multiple transports" : false,
        "reconnect" : false,
        "connect timeout" : 5000
    };


// The goal is to have this socket attempt to connect forever
// I would like to do it without the built in reconnects, as these
// are somewhat unreliable (reconnect* events not always firing)

function Test(){
    var self = this;
    events.EventEmitter.call(self);

    var socket;

    function reconnect(){
        setTimeout(go, 1000);
    }

    function go(){

        console.log("connecting to", url, socketOptions);

        socket = io.connect(url, socketOptions);

        socket.on('connect', function(){
            console.log("connected! wat.");
        });

        socket.on('error', function(err){
            console.log("socket.io-client 'error'", err);
            reconnect();
        });

        socket.on('connect_failed', function(){
            console.log("socket.io-client 'connect_failed'");
            reconnect();
        });

        socket.on('disconnect', function(){
            console.log("socket.io-client 'disconnect'");
            reconnect();
        });
    }

    go();
}

util.inherits(Test, events.EventEmitter);


var test = new Test();


process.on('exit', function(){
    console.log("this should never end");
});

When running it under node 0.11.0 I get the following:

$ node socketio_websocket.js 
connecting to ws://localhost:12345 { transports: [ 'websocket' ],
  'try multiple transports': false,
  reconnect: false,
  'connect timeout': 5000 }
socket.io-client 'error' Error: connect ECONNREFUSED
    at errnoException (net.js:878:11)
    at Object.afterConnect [as oncomplete] (net.js:869:19)
connecting to ws://localhost:12345 { transports: [ 'websocket' ],
  'try multiple transports': false,
  reconnect: false,
  'connect timeout': 5000 }
this should never end
Zach
  • 157
  • 3
  • 7

1 Answers1

4

The ECONNREFUSED is an exception you don't manage. Try with this:

process.on('uncaughtException', function(err) {
    if(err.code == 'ECONNREFUSED'){
        reconnect();
    }
}

Edit

Modify the options like this:

socketOptions = {
    "transports" : [ "websocket" ],
    "try multiple transports" : false,
    "reconnect" : false,
    'force new connection': true, // <-- Add this!
    "connect timeout" : 5000
};

and the reconnect function (look in the comments for the explanation)

function reconnect(){
    socket.removeAllListeners();
    setTimeout(go, 1000);
}

Probably socket.io reuse the same connection without creating a new one, forcing it the app works

Max Markson
  • 800
  • 1
  • 19
  • 34
  • 1
    That's not correct, `socket.on('error'...` is catching this error, and it's even calling reconnect again (logging the `connect to` code). At this point it bails. – Zach Apr 04 '13 at 13:27
  • Ops, you're right. Anyway you have to do a little correction, in the reconnect function you need to remove the listeners for the socket, otherwise you'll have multiple copies for every listener. – Max Markson Apr 04 '13 at 14:42
  • That's the ticket! The socket.io documentation needs a bit of work, found relevant parts you listed at [force new connection](https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO) and [removeAllListeners](http://stackoverflow.com/a/9696077/325652) – Zach Apr 04 '13 at 18:50