How to notify websocket's connected users from an unrelated request?

Hi!

I have an endpoint that receive webhook event from a third party service I use. When I receive a request from that third party, I’d like to notify all the users connected to the same account (via Room I suppose) about that new incoming data.

The issue is that I don’t have access to all the websockets connections from my /webhook handler.

I could create a class that stores all the websockets connections, per room, and list all the websockets connections on a specific room, and send the event one by one from there, but this won’t work well if I have more than one worker, and I’m pretty sure it’s not very efficient in term of error handling (what if the server goes down? is restarted? etc).

So here I am, hoping that I’m not the first and a pretty well working solution is available at my fingertips :slight_smile:

Thank you for your help and enjoy your weekend!

Iterating the connected handlers and notifying is the common pattern.

websockets underpins the sanic websockets implementation, and reading this: Broadcasting messages - websockets 10.0 documentation may help you find answers to your questions!

Thank you for your answer! That’s interesting, but they start with a decision that is problematic for me, and it’s the one I’m hoping to have an answer to:

They use a global dictionnary, “CLIENTS” to store all the connected users.

This works well if you have only one worker, but as soon as you have more, it won’t work.

Is there a currently existing solution for that? Or do I need to implement one on my end?

Also, does Sanic works like “websockets” or do I have to install it and connect the two?

I don’t understand the problem as stated. Each worker will have its own list of clients in the global context. You will have to decouple the messaging from the workers, probably using a pub/sub mechanism. You can do this with well known third-party tools such as RabbitMQ, NSQ, or Kafka. In this way, all workers are only responsible for notifying the clients that are connected to them, but the messages are distributed to all workers.

Sanic uses websockets for it’s own websockets implementation, as noted in my previous response.

My issue with how to connect the various workers with the Pub/Sub.

For instance, if I use Celery, it will run as an independent process, so the list of connected clients won’t be available. I can send an event from a worker that should be dispatched to all the clients connected on each workers, but how can I reach them then ?

Do I need to implement a infinte async loop on each Sanic instances (worker) that listen to any incoming pub/sub events related to websocket? or am I missing something?

Yes, I think you’re missing how the overall process works. Inside the websocket path you will handle the connection to the queue, and that will run forever until the process shuts down. Your message logic will need to be handled there. That involves both sending messages to the queue (publish) and receiving messages (subscribe) and then you need to determine at the worker level how those get processed to the clients that are connected.

Reading back the first link you sent, I missed the pub/sub implementation. Also, I’ve started working on it today and it makes more sense indeed!

Thank you for your help!

Also, the implementation from @ahopkins is really helpful:

I have a newer version of this coming soon to the docs
:wink:

1 Like

Here is the latest version