Using socket.io-redis & multiple servers/processes. How do I send a message to a specific socket ID with a callback? - node.js

I have multiple processes & servers, and am using socket.io-redis with session affinity (on Heroku).
When a client connects, I store a map of the client's user ID to the client's socket ID in Redis. Upon disconnecting, I delete the client's user ID from Redis.
I would like to be able to push a message to a client by looking up the client's socket ID, then sending a message to the specific socket ID.
One way to do this is io.to(socketId).emit(...). However, this does not allow me to send a callback with the message, which I would really like because I want to have confirmation of message receipt.
Another way I have found is io.connected[socketId].emit(...). The problem with this is that it does not scale to multiple servers, since the io.connected object may not necessarily be the same on every server since it only records sockets that the server itself is connected to. This solution does allow callbacks, however.
Is there a way to solve this so I can emit messages to a specific socket ID from any server or process, and also send a callback with the message?

Related

Need recommendation regarding rabbitmq

I am creating an chat application where I have a rest API and a socket.io server, What I want to do is the user will send messages to rest API, The api will persist those messages in database and then send these messages to the rabbimq queue then rabbitmq will send these messages to socket.io if the receiving user is online, Else the message will be stored in the queue and when the user will come online the user will retrieve these messages from the queue however I want to implement this in a way like whatsapp, The messages will be for a particular user and the user will only receive those messages which are meant for them i.e I don't want to broadcast messages I want only particular user to receive those messages
Chat should be a near-real-time application, there are multiple ways of modeling such a thing. First of all, you can use HTTP pooling, HTTP long pooling but some time ago there where introduced the new application-level protocol - web socket. It would be good for you, along with Stomp messages. Here you can check a brief example. And sending messages to specific users is also supported out-of-the-box example
1
To send messages to specific sockets you can use rooms: io.to(room).emit(msg). Every socket is a part of a room with the same name as the socket id.
2
I wouldn't wait for the message to be written to the database before sending it out through socket.io, your API can do both at once. When a user connects they can retrieve their messages from the database then listen for new ones on their socket.

How to take care of Network glitches with Socket.io communication

I am designing a system with Socket.io, Nodejs, Expressjs, Redis, Angularjs in which message delivery is very crucial.
Use Case:
My system needs to listen for notifications on resources which can also be shared among multiple users. Sockets are connected to the server with information about resource so that I can maintain a list of sockets for each resource. When there is a notification for that resource I send notification on every socket for that resource.
ResourceID1 = ["scoketID1", "socketID2"] // Two sockets listening to ResourceID1
I update this list on socket disconnect also by removing that specific socket id out or resourceID list.
This way I make sure notification is sent to every user which is sharing the resource and every session of that user along with every socket which can be multiple tabs for one session. In short "Every Socket".
I am also maintaining a hash for the resource notification so that every time there is a new notification for a resource the particular resource notification hash will be updated.
ResourceID1-notificationHash : { key1:"124", key2: "abc" }
The reason for doing this is that if the socket disconnected like user closed the tab or more importantly user Internet disconnected for some reason. and the server does not receive heart beat socket connection is made again and the last message for that resource is sent to that socket.
To make sure that particular socket(client) always receive the message is my implementation enough?
I know I can implement callbacks for an event but what I did is when a particular tab(socket)that was disconnected, is connected again I send the last message for that resource.
Are there any other network glitches which can cause problems for reliable message delivery?
My implementation is different in a sense that for message delivery I am not considering Users, I am considering sockets which can be multiple for just one user like one user can have multiple sessions at the same time lets say in firefox and chrome and then for each session he can have multiple tabs opened. Reason for choosing sockets is my resources can be shared among multiple users so that for one resource update I may have to send the message to multiple users each having multiple sessions and each session having multiple sockets.

How to send real time notification to single user using node.js and PHP

I am trying to integrate real time notifications with Node and socket.io in a Symfony Application. I have read a lot of information about this topic and have a working Node application.
nodeClient.js
var socket = io.connect( 'http://192.168.15.106:8080' );
$('a.sendSmile').click(function(){
socket.emit( 'message', { name: 'something' } );
});
socket.on('message', function(data){
console.log(data.name);
});
The problem now is with the above which is working perfectly I am able to send real time notification to all the users at once. But what's the best way to target a single user?
For example a user can send a smile to another user so only the second user should receive the notification and not all the users.
Should I make multiple listeners for node? or any other method to do this?
You need some way of identifying which socket that connected to your server is the one you want to send data to and then you can send to just that socket. You can keep track of user names when users connect or if you have some auth system, you can keep track of which socket belongs to which authenticated user.
Your server holds a list of connected sockets. Each connected one at a time and triggered a connection event on your server when they connected. Your application needs to create a way of knowing which of those connected sockets you want to send the data to. This is not something you've described anything about how you want that to work so we can't really help more specifically.
You can dispatch a notification to single user if you can discriminate that user. For example you can get a user_id on client connection to your nodejs server (the user_id is send from client, inside message) and save it in a key-value store (like Redis, memcache, ...). In this way you can correctly dispatch the notification, arrived from the server (like Symfony2 application), to right user.
I suggest you use Redis, both as a key-value store and for its implementation pattern of the publish/subscribe usable as a channel of communication between the server and the application of realtime.

Two instances of one socket.io connection

In our app, every time a user signs in a new connection in socket.io is created. So if a user signs in simultaneously on more devices, they behave as separate connections. Instead of creating a new connection every time, I'd like to check whether the user is already connected to socket.io and if he is, I'd like to connect him to already established connection. How can this be done?
From the socket.io perspective, those ARE two connections. But if it was my app, I would do something like this:
add a user identifier (userid, username, something you identify users by) to both the users' socket.io connection (so, each time you send a message to the client, you also pass this id)
pass this id also to the client-side code on init.
So now the socket on the server side has its' socket.io id, but also your user id. Anyway, to proceed:
send this user-id to the client in it's javascript files.
on the client-side code, make a small adjustment to socket.io handler - for each received message (say, broadcast), you can now check if it's your current user-id and instead of saying 'User #351 says Hi' you can say 'You said Hi on another device' or something like that.
Of course, I'm not socket.io expert, there's could already exist a framework or lib addressing this.

how to send a message to individual clients with socket.io with multiple server processes?

I'm about to begin with socket.io and this is more of a theoretical question,
let's say that I want to send a message to a specific user with socket.io,
normally I would have to store the socketid with the relevant userid and when sending, get the socketid and send to.
but what if I have mutliple server processes running ? I'll have to make sure the correct server that the client is actually connected to does the sending. is it possible ?
For multiple server instances, you need to have a caching service (memcache, redis) for authentication and a central message queue service (stormMQ, rabbitMQ, AQ, java-based mq) where all your node instances bind to. Thus, a Node instance binds to the message queue for each client / channel / whatever, and all the other bound Node instances receive the messages and forward them to the client.
The problem is typically about how to play with a WebSocket cluster:
Several front-end servers which will be in charge of handling bidirectional connections with each client. They form the WebSocket cluster.
Several back-end servers which will be in charge of handling the business logic of your application.
Each time the back-end wants to inform the client, it will send a request to the WebSocket cluster which has the responsibility to communicate with the client.
A possible scenario:
Identify each WebSocket cluster's server with a unique id.
Identify each client with a unique id.
Each time a client will connect one of your WebSocket cluster's server, store its unique id along with the server's unique id in a a distributed key/value like database.
Thus you know which client is connected with which server.
The next time your back-end application wants to notify a client there are two possibilities:
The pair (clientId, serverId) is not present in the database and you cannot inform the client.
The pair (clientId, serverId) is present in the database, then you have to ask to the server identified by serverId to notify the client identified by clientId.
Notes:
Each WebSocket cluster's server can run a node.js instance supercharged with socket.io. It has to provide a route which will take the clientId as a parameter and will use socket.io to notify this client. Indeed, socket.io is aware of whcih client is using which socket on this server.
Every time your server will crash, you have to clean your database and remove all pairs which contain the server id.
Deploying a WebSocket cluster can be tedious, so you have commercial offers like Kaazing.
A good distributed key/value like database is Riak. It is better than Redis or Memcached for the above purpose because it can be easily distributed in a data-center and over several data-centers.

Resources