Erlang Pub/Sub using Redis and websockets - websocket

My goal is to create an application that I can use to manage pub/sub for various clients. The application should be able to receive new topics via an API and then accept subscribers via a websocket connection.
I have it working, but am aware the current solution has many flaws. It works currently as follows:
I have a chicago_boss app, that has a websocket endpoint for clients to connect to, once the client connects, I add the Pid for that Websocket connection to a list in Redis.
Client connects to "ws://localhost:8001/websocket/game_notifications"
The Pid for that Websocket connection is added to Redis using LPUSH game_notifications_pids "<0.201.0>".
3.The last 10 messages in Redis for game_notifications are sent to the websocket Pid
A new message is posted to "/game_notifications/create"
Message is added to redis using LPUSH game_notifications "new message"
All Pids in Redis with key game_notifications_pids are sent this new message
On closing of the websocket the Pid is deleted from the Redis list
Please let me know what problems people see with this setup? Thanks!

Related

How to store websocket id in Gorilla using Redis for accessing the socket connection across the processes

I would like to know the best way to store the websocket client id or connection in Redis. I am not building a chat app so I do not need to broadcast but send messages to specific websockets.
Need help.

Working of websocket services in clustered deployment

Lets say I have a websocket implemented in springboot. The architecture is microservice. I have deployed the service in kubernetes cluster and I have 2 running instance of the service, the socket implementation is using stomp and redis as broker.
Now the first connection is created between a client and one of the service. Does all the data flow occur through the client and the connected service? Would the other service also have a connection? Incase the current service goes down would the other service open up a connection?
Now lets say I'am sending some data back to the client which comes through a kafka topic. One of the either service could read it. If then would either of them be able to send the data back to the client?
Can someone help me understand these scenarios?
A websocket is a permanent connection. After opening it, it will be routed through kubernetes to a fixed pod. No other pod will receive the connection.
If the pod goes down, the connection is terminated.
If a new connection is created, for example by a different user, it may be routed to a different pod.
What data is transmitted, for example with kafka as source, is not relevant in this context. It could be anything.

When 2 servers connected to same socket redis adapter. Is both of them get messages from the client same time?

I have two servers server-a and server-b.
For using socket.io usually, the two servers are using redis adapter. Then the client can connect to server-a or server-b.
Now the question is: If the client is connected to server-a and emit a message. Is server-b have an option to get the message?
The client code:
io.emit('sendMessage',myMessage)
The Server-a Code:
io.on('sendMessage',function(){
console.log('Server A got the message')
}
The Server-a Code:
io.on('sendMessage',function(){
console.log('Server B got the message')
}
The client is connected only to server-a. server-a & server-b are using the same redis adapter.
The question is: When client emit a message, is server-b will get it? (Server-B is only connected to the same redis)
What I want to do: I have several servers that should do an action, based on client request. When client request something, all the servers needs to start works. I thought to do with socket.io, and to keep one connection between the client and on of the servers.
All the servers will use socket.io to get the same message from the client.
If you are using the redis adapter properly with all your servers, then when you do something like:
io.emit('sendMessage',myMessage)
from any one of your servers, then that message will end up being sent to all the clients connected to all your servers. What happens internally is the message is sent to a redis channel which all the servers are listening to. When each server gets the message, they then broadcast to all their users but these last steps are transparently handled for you by the redis adapter and redis store.
So, io.emit() is used to send to all connected clients (which uses all the servers in order to carry out the broadcast). It is not used to broadcast the same message directly to all your servers so that they can each manually process that message.
To send to each of your servers, you could probably use your own custom redis publish/subscribe channel messages since each server is already connected to redis and this is something that redis is good at.
Or, you could designate one master socket.io server and have all the other servers connect to it with socket.io. Then any server could ask the central server to broadcast a message to all the other servers.

Connect/disconnect from ActiveMQ topic on camel websocket connection/disconnection

I've got the following camel route which listens for messages on an ActiveMQ topic and immediately sends them to all connected web socket clients. This is working fine, but the connection to the topic is made as soon as the route builder is initialised.
from("activemq:topic:mytopic").routeId("routeid").to("websocket://test?sendToAll=true");
What I need is to only connect to the topic when one or more clients are connected to the web socket. Once there are no more connections I want to stop listening on the topic. Is this possible?
According to me there is no proper way to do this. The only way this can be achieved is override Jetty WebSocket code. Once you override Jetty Websocket code you get the flexibility to write your own custom code in open and close websocket.
Maintain a List for all websocket clients in open websocket. Check for close websocket and remove it from the list to know how many are connected or disconnected. Or keep a counter on open and close websocket.
Once all websocket clients get closed suspend the route so that your messages stay in the topic or queue.
If any client gets connected to websocket, resume the route so that the messages reach the particular client connected.

RabbitMQ with Websocket and Gevent

I'm looking forward to develop a realtime API for my web application using Websocket. For this I'm using RabbitMQ as the broker and My backend is based on python (gevent + websocket),and Pika/Puka as rabbitmq client.
The problem I'm facing here is that, how we can use websocket to connect with rabbitMQ. After the initial websocket connection establishment, the socket object wait for new messages from client, and in the case of rabbitMQ, we need to setup a consumer for it, so it will process the message when it receive one. We can take this in this way,
Clients are established connection with server via full-duplex websocket.
All clients should act as RabbitMQ's consumer after initial websocket handshake, so they all get updates when a client gets some message.
When new message arrives at websocket, that client will send it to RabbitMQ, so at this time this client act as publisher.
The problem is Websocket wait for a new message, and the RabbitMQ consumer wait for new message on its channel, I'm failed to link these two cases.
I'm not sure whether this is a wrong method ...
I'm unable to find a method to implement this scenario.If I'm going wrong way or is there any alternate method ?, please help me to fix this.
Thank you,
Haridas N.
I implemented similar requirement with Tornado + websocket + RabbitMQ + Pika.
I think this were already known method. Here is my git repo for this web chat application.
https://github.com/haridas/RabbitChat
It seems very difficult to the similar thing with gevent/twisted because the rabbitMQ clients couldn't supporting the event loops of gevent/twisted.
The pika has tornado adapter, so that makes this easy to setup. Pika development team working on the twisted adapter also. I hope they will release it very soon.
Thanks,
Haridas N.
http://haridas.in.
A simple solution would be to use gevent.queue.Queue instances for inter-greenlet communication.

Resources