leporo / tornado-redis

Asynchronous Redis client that works within Tornado IO loop.
666 stars 162 forks source link

Pub/Sub duplicate messages #58

Closed canhduong28 closed 10 years ago

canhduong28 commented 10 years ago

Hi,

I'm writing a small application which allows users to publish/subscribe multi channels at a time and I chose Tornado-Redis to implement this feature. The scenario is that one message would be sent to multi channels, but if a user who subscribed all these channels, then he/she should get the message one time only. Right now, users keep receiving duplicate messages from the Pub/Sub handler.

[Solutions]: I have an idea that I will override the SockJSSubscriber class to use a bloom filter to avoid duplicating messages sent over this object. If you guys have any better idea, just let me know. I would highly appreciate that.

Thanks, -Canh

leporo commented 10 years ago

Hi Canh,

Your idea seem fine for me.

Here are my thoughts:

            broadcasters = list(self.subscribers[msg.channel].keys())
            if broadcasters:
                broadcasters[0].broadcast(broadcasters, str(msg.body))

Thanks for your idea.

It would be great if you share your implementation when you have it :)

canhduong28 commented 10 years ago

Hi Vlad,

Thank for you suggestions, I highly appreciate that.

However, I came up with a solution that I will override the broadcast method of SockJSConnection class.

Implementation code would look like that:

class SubscriptionHandler(sockjs.tornado.SockJSConnection):

def __init__(self, *args, **kwargs):
    super(SubscriptionHandler, self).__init__(*args, **kwargs)
    self.bloom_filter = pyreBloom.pyreBloom(str(uuid.uuid4()), 10000, 0.01)

def broadcast(self, clients, message):
    msg_id = utils.get_msgId(message)
    if not self.bloom_filter.contains(msg_id):
        self.session.broadcast(clients, message)
        self.bloom_filter.add(msg_id)

The bloom filter serves only when the session is activated, it will be deleted when connection is closed. So this implementation is quite basic. But it worked for me and I'm happy with that.

Thank you all and happy coding :)

leporo commented 10 years ago

Thank you for sharing your code. I highly appreciate that.

Do you mind if I share my thoughts about it?

Thanks again! It was fun :)

canhduong28 commented 10 years ago

Thank you for sharing your thoughts, I highly appreciate that.

  1. I agreed that using message + client ID pair will be more efficient. I will implement this approach to improve the process.
  2. I already knew that. This is why I chose the SockJSConnection to override instead of SockJSSubscriber :)

It was really fun for me too.