2

I am creating a long-polling chat application on nodeJS without using Socket.io and scaling it using clusters.

I have to find a way to store all the long-polled HTTP requests and response objects in such a way that it is available across all node clusters(so that when a message is received for a long-polled request, I can get that request and respond to it)

I have tried using redis, however, when I stringify http request and response objects, I get "Cannot Stringify Cyclic Structure" Error.

Maybe I am approaching it in a wrong way. In that case, how do we generally implement lon-polling across different clusters?

2 Answers2

1

If you are sure you want to store all the request and responses, have a look at this question. Serializing Cyclic objects

you can also try cycle.js

However, I think you would only be interested in serializing few elements from request/response. An easier (probably better too) approach would be to just copy the required key/value pairs from request/response object in to a separate object and store them.

Community
  • 1
  • 1
d_shiv
  • 1,670
  • 10
  • 8
1

What you're asking seems to be a bit confused.

In a long-polling situation, a client makes an http request that is routed to a specific HTTP server. If no data to satisfy that request is immediately available, the request is then kept alive for some extended period of time and either it will eventually timeout and the client will then issue another long polling request or some data will become available and a response will be returned to the request.

As such, you do not make this work in clusters by trying to centrally save request and response objects. Those belong to a specific TCP connection between a specific server and a specific client. You can't save them and use them elsewhere and it also isn't something that helps any of this work with clustering either.

What I would think the clustering problem you have here is that when some data does become available for a specific client, you need to know which server that client has a long polling request that is currently live so you can instruct that specific server to return the data from that request.

The usual way that you do this is you have some sort of userID that represents each client. When any client connects in with a long polling request, that connection is cluster distributed to one of your servers. That server that gets the request, then writes to a central database (often redis) that this userID userA is now connected to server12. Then, when some data becomes available for userA, any agent can lookup that user in the redis store and see that the user is currently connected to server12. So, they can instruct server12 to send the data to userA using the current long polling connection for userA.

This is just one strategy for dealing with clustering - there are many others such as sticky load balancing, algorithmic distribution, broadcast distribution, etc... You can see an answer that describes some of the various schemes here.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • This makes a lot of sense. Can you please guide me as to how a serverX can direct a serverY to send a response back. I have heard that workers can communicate only via the master – Sanchit Mehta Aug 15 '15 at 20:44
  • @SanchitMehta - there are many ways for different servers to communicate. Without only a few lines of node.js code you could have each of your node.js servers listen with an http server on a custom port (often called a control port) and then just send an http request to that server to tell it to send the data to userA. You would then make sure that the control port was not open to the outside world so that it could only be used by your other servers from behind your firewall. – jfriend00 Aug 15 '15 at 21:35
  • @jfriend00- I have 4 clusters. I can make all of them listen to a port(say 8080). Now if clusterA is long-polling a request and clusterB gets a new message, then clusterB can send a request to the server running in Port 8080. Is my understanding right? Now suppose clusterB sends a request to port 8080, how can we ensure that the correct cluster i.e. clusterA gets this request(4 clusters are also listening to 8080). – Sanchit Mehta Aug 16 '15 at 20:09
  • @SanchitMehta - there are a number of different strategies. To start with, you don't want to send to a port that is being load-balanced to your cluster. You will want to send to a specific server where the user is connected. The various schemes you can choose are described [here](http://stackoverflow.com/questions/31924311/socket-io-over-multiple-servers-w-o-redis/31924481#31924481). Which scheme you select determines how you know which specific server to send the message to or whether you broadcast it to all of them. – jfriend00 Aug 16 '15 at 20:33
  • @SanchitMehta - I guess I should add that if all your clusters are on the same server, then you may need each to have their own separate control port number so you can each the desired server by picking the right port number. – jfriend00 Aug 16 '15 at 20:44
  • @jfriend00- Instead of listening to a port, I have used mqtt and subscribed each cluster to their Process Id(process.pid). Now when I am getting a new chat message, I am just checking redis store for any user polling for that message and find the PID and then publish the message to the designated mqtt subscription(don't know what it is called exactly). This worked like a charm. Thanks a lot for your help :) – Sanchit Mehta Aug 18 '15 at 05:00