Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Socket.io + NodeJS doesn't work on Heroku

I am doing an API and it's on Heroku. But I am having some problems with the socket.io only on the heroku side, when I test it in local everything goes fine. The API is completely independent of the frontend, so they are in a different domains (and a different hosts). The problem is that on production, I don't get succeed in connect the sockets...

I have some questions, all of that are about the socket.io configuration on heroku. I know that there are some posts with some information about that, but the posts I found it was with old versions of sockets.io or old versions of heroku (heroku seems to has changed the websockets stuff the past July):

  • I don't know if I need to activate something before run socket.io on heroku. I read some posts about that, but all seems to be old... I tried to activate Websockets with: $ heroku labs:enable websockets but the response that I got it was: ! No such feature: websockets.

  • Do I have to specify a port, or Heroku has an automatic port for that?

  • Do I need two connections? One to listen the POST/GET/PUT/DELETE and another to the sockets?

app.js

    var express = require('express');
    var app = module.exports = express();
    var port = process.env.PORT || 5000;
    var port_s = 3000;
    var server = require('http').createServer(express);
    ...
    app.listen(port);
    server.listen(port_s);

    require('./config/socket-io')(app, server, secret);
    app.post('/user', routes.users.register);
    ...

socket-io.js

module.exports = function(app, server, secret) {
    var clients = {};
    console.log("initiating sockets...");
    var sio = require('socket.io').listen(server);

    sio.sockets.on('connection', function (socket) {
        clients[socket.id] = socket;
        console.log("...new connection: "+socket.client.id);
        socket.emit('identification', { data : socket.client.id });

        socket.on('newShoutOut', function(data) {
            var receptor    = data.idTo;
            var emiter      = socket.client.id;
            //console.log("...new shout out from " +emiter+ " to "+receptor);
            var elem = findElement(sio.sockets['sockets'], 'id', receptor);
            sio.sockets.sockets[elem].emit('privateShoutout',{ data : data.data, from : emiter });
        });

        socket.on('disconnect', function() {
            //console.log("..."+socket.client.id + " disconnected");
        });
    });
};

function findElement(arr, propName, propValue) {
    for (var i=0; i < arr.length; i++) {
        if (arr[i].id === propValue)
            return i;
    };
}

I repeat, everything works on localhost. I tried the API on localhost:5000 and the client app on localhost:80 and all the sockets work fine.

Thank you.

like image 867
newpatriks Avatar asked Jul 29 '14 10:07

newpatriks


People also ask

Does Heroku allow WebSockets?

It gives you the flexibility of a TCP connection with the additional security model and meta data built into the HTTP protocol. For more details on the WebSocket protocol refer to RFC 6455, which is the version supported on Heroku.

Does Heroku support node JS?

Initially, it supported only Ruby sites but now supports various languages, including JavaScript with Node. js. Heroku also has Docker support so that you can deploy just about anything to it. This tutorial will teach you how to build a small application using the Express framework for Node.


1 Answers

So there's a couple things here. If you'd like to use Heroku's Websocket service (which is pretty great actually), you're going to need to rework your code to use the einaros/ws implementation of websockets--and then add the service via heroku command line. https://github.com/einaros/ws/blob/master/doc/ws.md

however, since you've already coded your app to socket.io, I would simply rework how you're instantiating the socket.io library:

var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server),

server.listen(process.env.PORT || 3000);

This should solve your issue, but let me know what the logs show. I think the hang up is that your app, and your socket are running on two different ports.

After you've created your sever, you can listen for socket events with:

io.sockets.on('connection', function(socket) { //'connection' or any other event

Hope this helps.

like image 197
bencripps Avatar answered Sep 24 '22 13:09

bencripps