gevent-socketio icon indicating copy to clipboard operation
gevent-socketio copied to clipboard

Server-level broadcast

Open philipn opened this issue 13 years ago • 10 comments

Currently, an individual socket can broadcast using the BroadcastMixin. But what if you want to spin up a greenlet -- independent of a particular connection -- and have it publish to all the sockets on the server? In my case I'm streaming some data from an API and want to send it to all the sockets. Here's what I'm doing:

def broadcast_event(server, ns_name, event, *args):
    pkt = dict(type="event",
               name=event,
               args=args,
               endpoint=ns_name)

    for sessid, socket in server.sockets.iteritems():
        socket.send_packet(pkt)


def send_stuff(server):
    for thing in stream:
        broadcast_event(server, '/myapp', 'echo', thing)

...

if __name__ == '__main__':
    print 'Listening on port http://0.0.0.0:8080 and on port 10843 (flash policy server)'
    server = SocketIOServer(('0.0.0.0', 8080), Application(),
        resource="socket.io", policy_server=True,
        policy_listener=('0.0.0.0', 10843))
    gevent.spawn(send_things, server)
    server.serve_forever()

Would this broadcast pattern be valuable to include as a method on the SocketIOServer class?

philipn avatar Aug 01 '12 01:08 philipn

It looks like we can also do this, which is a little awkward:

def broadcast_msg(server, tweet):
    for socket in server.sockets.values():
        if '/tweets' in socket:
            socket['/tweets'].emit('tweet', tweet)

but better because we don't have to manually construct the packet object (which a user of gevent-socketio probably shouldn't ever have to worry about).

Awkward because I have to check to see if the namespace is in the socket before sending because of the order things happen in my example.

philipn avatar Aug 01 '12 21:08 philipn

You really ought to use something like redis or zeromq for passing messages between sockets, because a typical production deployment will prefork multiple server instances, and you would otherwise have no visibility of sessions belonging to to another server instance.

dswarbrick avatar Aug 01 '12 22:08 dswarbrick

This is true of emit(), etc as well, no? If using multiple servers the message won't be sent to everyone without using some kind of external message queue or other trickery.

But for many case the simple default single-server works great.

On Aug 1, 2012, at 3:18 PM, Daniel [email protected] wrote:

You really ought to use something like redis or zeromq for passing messages between sockets, because a typical production deployment will prefork multiple server instances, and you would otherwise have no visibility of sessions belonging to to another server instance.


Reply to this email directly or view it on GitHub: https://github.com/abourget/gevent-socketio/issues/67#issuecomment-7441873

philipn avatar Aug 01 '12 22:08 philipn

Something like broadcast_event_not_me() is only capable of sending the event to all sockets connected to a single parent server. So if you have multiple server instances, they will need to subscribe to some sort of message queue like redis, and listen for messages from other server instances.

dswarbrick avatar Aug 01 '12 22:08 dswarbrick

@dswarbrick Yeah, the SocketIO server API is by its very nature limited to a single server. The JS SocketIO server code has the notion of different stores, and you can use RedisStore to transparently interface with a redis backend - http://www.ranu.com.ar/2011/11/redisstore-and-rooms-with-socketio.html. We should probably do something similar! (Would be a fun project!) But that's a larger issue.

philipn avatar Aug 01 '12 23:08 philipn

@dswarbrick Tracking in #72

philipn avatar Aug 01 '12 23:08 philipn

@philipn : it's funny to see we both worked on the same twitter implementation and ran across the same problem.

Maybe you'll want to see my modest contribution : https://github.com/ultrabug/geventweet

ultrabug avatar Aug 02 '12 09:08 ultrabug

Whoa, that is funny! And we did it at like the exact same time, too.

I'm not sure about the session global approach you use. I think using the server object is more natural and more in line with what the JS implementation does. What do you think?

philipn avatar Aug 02 '12 20:08 philipn

@philipn : sure I agree with you on the principle, that's why I also searched for a better solution and found this issue but I think @dswarbrick is right, we ought to use a proper message queuing layer rather than trying to hack the server. Maybe I'll take the time to implement this in geventweet.

ultrabug avatar Aug 03 '12 07:08 ultrabug

@philipn @ultrabug I'd like to discuss this more with you guys if you are interested. I have some spare time now. I think we should support scalable datastores for broadcasting like redis and zmq out of the box.

sontek avatar Nov 22 '12 21:11 sontek