leporo / tornado-redis

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

Self is Nonetype, attribute error raised #25

Closed gtzilla closed 10 years ago

gtzilla commented 11 years ago

I am attempting to implement a simple chat client with connection pooling. Working from the demo, I have created the following ChatHandler class.

https://gist.github.com/gregory80/300e377b91ceac2a3e04

While attempting to use this class in a basic call, an attribute error is generated (See stack trace below). Its not clear why "self" here is Nonetype, or why it would generate an attribute error for write_message.

This exception manifests itself running tornado under gunicorn, and only after at least one connection has been already opened.

    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 34, in run
    22:38:51 web.1  |     WSGIApplication("%(prog)s [OPTIONS] APP_MODULE").run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/app/base.py", line 131, in run
    22:38:51 web.1  |     Arbiter(self).run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/arbiter.py", line 173, in run
    22:38:51 web.1  |     self.manage_workers()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/arbiter.py", line 460, in manage_workers
    22:38:51 web.1  |     self.spawn_workers()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/arbiter.py", line 512, in spawn_workers
    22:38:51 web.1  |     self.spawn_worker()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/arbiter.py", line 485, in spawn_worker
    22:38:51 web.1  |     worker.init_process()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/workers/base.py", line 104, in init_process
    22:38:51 web.1  |     self.run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/gunicorn/workers/gtornado.py", line 96, in run
    22:38:51 web.1  |     self.ioloop.start()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/ioloop.py", line 271, in start
    22:38:51 web.1  |     self._run_callback(callback)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/ioloop.py", line 421, in _run_callback
    22:38:51 web.1  |     callback()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/iostream.py", line 311, in wrapper
    22:38:51 web.1  |     callback(*args)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/stack_context.py", line 229, in wrapped
    22:38:51 web.1  |     callback(*args, **kwargs)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornadoredis/connection.py", line 125, in read_callback
    22:38:51 web.1  |     callback(*args, **kwargs)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 383, in inner
    22:38:51 web.1  |     self.set_result(key, result)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 315, in set_result
    22:38:51 web.1  |     self.run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 345, in run
    22:38:51 web.1  |     yielded = self.gen.send(next)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornadoredis/client.py", line 447, in process_data
    22:38:51 web.1  |     callback(response)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 383, in inner
    22:38:51 web.1  |     self.set_result(key, result)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 315, in set_result
    22:38:51 web.1  |     self.run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 345, in run
    22:38:51 web.1  |     yielded = self.gen.send(next)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornadoredis/client.py", line 462, in consume_multibulk
    22:38:51 web.1  |     callback(tokens)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 383, in inner
    22:38:51 web.1  |     self.set_result(key, result)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 315, in set_result
    22:38:51 web.1  |     self.run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 345, in run
    22:38:51 web.1  |     yielded = self.gen.send(next)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornadoredis/client.py", line 447, in process_data
    22:38:51 web.1  |     callback(response)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 383, in inner
    22:38:51 web.1  |     self.set_result(key, result)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 315, in set_result
    22:38:51 web.1  |     self.run()
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornado/gen.py", line 345, in run
    22:38:51 web.1  |     yielded = self.gen.send(next)
    22:38:51 web.1  |   File "/Volumes/projects/javascript/gif_chat/venv/lib/python2.7/site-packages/tornadoredis/client.py", line 1014, in listen
    22:38:51 web.1  |     callback(result)
    22:38:51 web.1  |   File "PATH/app/webapp.py", line 86, in pubsub_message
    22:38:51 web.1  |     traceback.print_stack()
leporo commented 11 years ago

Please, show me the code for the tredis_client function. I need it to get the full picture of what may happen.

Meanwhile, I recommend to not use a connection pool for Pub/Sub operations. If you need to limit a number of opened connections you may do it using a global or class variable (just increment it in init and decrement in close method).

Consider using a global channel listener as other option, especially if you implement a multiuser/conference chat.

gtzilla commented 11 years ago

I implemented connection pooling after running redis out of connections, which subsequently led to redis filing its' log file with connection error log events and growing to over 160gbs.

As suggested, i will attempt to remove connection pooling.

see tredis_client definition, below

import tornadoredis 
import os
CONNECTION_POOL = tornadoredis.ConnectionPool(max_connections=150,
                                              wait_for_available=True)

def get_redis_url():
    return urlparse.urlparse(os.environ.get('REDISTOGO_URL', 'redis://localhost:6379'))

def tredis_client(db_index=None):
    # logger.warn("conn pool %s" % CONNECTION_POOL)
    if not db_index:
        db_index = tornado.options.options.db_index
    uri = get_redis_url()
    return tornadoredis.Client(
        host=uri.hostname,
        port=uri.port,
        password=uri.password,
        connection_pool=CONNECTION_POOL, 
        selected_db=db_index)   
leporo commented 11 years ago

Thank you for the source code. I'll try to reproduce the issue.

leporo commented 11 years ago

Please take a look at new helper classes located in tornadoredis.pubsub module. You may find them useful when implementing Pub/Sub subscriptions in your Tornado application.

Please, advise: do you still need a fix for this issue?