gevent-socketio
gevent-socketio copied to clipboard
Server-level broadcast
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?
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.
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.
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
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 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.
@dswarbrick Tracking in #72
@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
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 : 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.
@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.