WebSocket pushing database updates
architecture, heroku, playframework-2.2, redis, websocket
Solution
This is actually a pretty common scenario, where you have three components:
- A cluster of stateless web servers that maintain open connections with all clients (load balanced across the cluster, obviously)
- A persistent main data storage - Neo4j in your case
- A messaging/queueing backend for broadcasting messages across channels (thus across the server cluster) - Redis
Your requirement is for new clients to receive an initial feed of the recent messages, and any consequent messages in real-time. All of this is implemented in your connection handlers.
Essentially, this is what your (pseudo-)code should look like:
class ConnectionHandler:
redis = redis.get_connection()
def on_init():
self.send("hello, here are all the recent messages")
recent_msgs = fetch_msgs_from_neo4j()
self.send(recent_msgs)
redis.add_listener(on_msg)
self.send("now listening on new messages")
def on_msg(msg):
self.send("new message: ")
self.send(msg)
The exact implementation really depends on your environment, but this is the general flow of things.
Problem
Most of the articles on the web dealing with WebSockets are about in-memory Chat. I'm interested in kind of less instant Chat, that is persistent, like a blog's post's comments. I have a cluster of two servers handling client requests. I wonder what could be the best strategy to handle pushing of database update to corresponding clients. As I'm using Heroku to handle this cluster (of 2 web dynos), I obviously read this tutorial aiming to build a Chat Room shared between all clients. It uses Redis in order to centralize coming messages; each server listening for new messages to propagate to web clients through websocket connections. My use case differs in that I've got a Neo4j database, persisting into it each message written by any client. My goal is to notify each client from a specific room that a new message/comment has just been persisted by a client. With an architecture similar to the tutorial linked above, how could I filter only new messages to propagate to user? Is there an easy and efficient way to tell Redis: "(WebSocket saying) When my client initiates the websocket connection, I take care to make a query for all persisted messages and sent them to client, however I want you (Redis) to feed me with all NEW messages, that I didn't send to client, so that I will be able to provide them." How to prevent Redis from publishing the whole conversation each time a websocket connection is made? It would lead to duplications since the database query already provided the existing contents at the moment.