leporo / tornado-redis

Asynchronous Redis client that works within Tornado IO loop.
667 stars 163 forks source link

Handling disconnections during blocking commands (e.g. BLPOP) #24

Closed lessandro closed 11 years ago

lessandro commented 11 years ago

When the client is waiting on a blocking command, if a disconnection occurs the caller is never notified.

Sample code:

import tornado, tornadoredis

@tornado.gen.engine
def run():
    r = tornadoredis.Client()
    r.connect()
    while True:
        result = yield tornado.gen.Task(r.blpop, 'key')
        print result

if __name__ == '__main__':
    run()
    tornado.ioloop.IOLoop.instance().start()

Run the code above, then stop redis-server. This exception will be thrown by the library.

Ideally the client should be notified about the exception so that it can handle it (reconnecting, for instance), but currently it just fails silently.

I pushed a solution to my personal tornado-redis fork that simply calls the client callback passing the exception to it: https://github.com/lessandro/tornado-redis/commit/1795b8f8064fdf4c6098ee0ba8b88fb7471a8a50

This is how i handle disconnections: https://github.com/lessandro/ircd/blob/09df12a6bce4f60ee57b90a3f8d31f52e25ee7ee/servers/redisutil.py#L48

lessandro commented 11 years ago

try: except: doesn't catch the exception when connect() is called outside the gen.engine'd function. I'm not sure what's going on.

import tornado, tornadoredis

r1 = tornadoredis.Client()
r1.connect()

@tornado.gen.engine
def loop1():
    while True:
        try:
            print 'waiting1'
            yield tornado.gen.Task(r1.blpop, 'key')
        except:
            print 'err1'
            return

r2 = tornadoredis.Client()

@tornado.gen.engine
def loop2():
    r2.connect()
    while True:
        try:
            print 'waiting2'
            yield tornado.gen.Task(r2.blpop, 'key')
        except:
            print 'err2'
            return

loop1()  # does not catch the exception
loop2()  # catches the exception

tornado.ioloop.IOLoop.instance().start()

EDIT: I upgraded my tornado and the problem disappeared.