我用龙卷风和tornadoredis写了一个彗星演示,演示可以工作,但有时会发生错误,我不知道如何解决它。有人可以帮帮我吗?
错误:
[E 150410 18:18:44 web:1421] Uncaught exception GET /comet?channelKey=channel%3Awx4g1nej7fuu&message_id=193 (127.0.0.1)
HTTPServerRequest(protocol='http', host='tornado.test.com', method='GET', uri='/comet?channelKey=channel%3Awx4g1nej7fuu&message_id=193', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Remote-Addr': 'xxx', 'Service': 'android', 'X-Forwarded-For': 'xxx', 'User-Agent': 'Apache-HttpClient/UNAVAILABLE (java 1.4)', 'Host': 'tornado.test.wolonge.com', 'X-Requested-With': 'XMLHttpRequest', 'X-Real-Ip': 'xxx', 'Cookie': 'logintoken=gsvimqqefr8f9duu66emjrbbe5_8be6AsNqW%2B3kwH7OsnT0OAKbZNNqnzabDIVcFDE8TvyozQ7h'})
Traceback (most recent call last):
File "/usr/lib64/python2.6/site-packages/tornado/web.py", line 1302, in _stack_context_handle_exception
raise_exc_info((type, value, traceback))
File "/usr/lib64/python2.6/site-packages/tornado/web.py", line 1489, in wrapper
result = method(self, *args, **kwargs)
File "/home/wwwroot/wolongge_mobile/app/tornado_push/models/ws_handle.py", line 53, in ready_finish
self.finish(res)
File "/usr/lib64/python2.6/site-packages/tornado/web.py", line 863, in finish
raise RuntimeError("finish() called twice. May be caused "
RuntimeError: finish() called twice. May be caused by using async operations without the @asynchronous decorator
我的代码在这里:
class GroupChat(tornado.web.RequestHandler):
def initialize(self):
print 'GroupChat here'
self.c = tornadoredis.Client(host=CONFIG['REDIS_HOST'], port=CONFIG['REDIS_PORT'], password=CONFIG['REDIS_AUTH'])
@tornado.gen.coroutine
@tornado.web.asynchronous
def get(self):
try:
self.key = self.get_argument('channelKey')
# print 'key:%s' % self.key
self.key = url_unescape(self.key);
# print 'key:%s' % self.key
if(self.key):
yield tornado.gen.Task(self.c.subscribe, self.key)
self.c.listen(self.on_message)
except Exception, e:
self.c.disconnect()
self.ready_finish('Bad Request (Missing argument)')
print e
pass
@tornado.web.asynchronous
def on_message(self, msg):
if (msg.kind == 'message'):
print msg
message_id = int(self.get_argument('message_id'))
max_message_id = int(msg.body)
if(message_id < max_message_id):
self.ready_finish('1')
else:
self.ready_finish('0')
elif (msg.kind == 'unsubscribe'):
self.c.disconnect()
@tornado.web.asynchronous
def ready_finish(self, res):
if (self.c.subscribed):
self.c.unsubscribe(self.key)
self.finish(res)
def on_connection_close(self):
print 'on_connection_close here'
另一个问题,@ tornado.web.asynchronous是正确的使用方法吗?每个方法都有@ tornado.web.asynchronous ...
答案 0 :(得分:2)
通常,避免混合协同程序和异步回调样式。在这里,你的get()方法是一个协程,它会在返回时自动完成请求,但它也启动了基于回调的listen()
,它将在稍后尝试完成请求。
你需要添加某种协调来确保get()协程在回调完成请求之前不会返回(toro.Event对此有利)或者摆脱{{1订阅时使用显式回调。在任何一种情况下,您应该只在yield gen.Task
方法中使用@asynchronous
或@coroutine
,而在其他方法中不允许装饰。
答案 1 :(得分:0)
仅@tornado.web.asynchronous
方法需要get
。同时删除@tornado.gen.coroutine
方法下的get
。
正如@tornado.web.asynchronous
的文档中所述
http://tornado.readthedocs.org/en/latest/web.html#tornado.web.asynchronous
此装饰器应仅应用于HTTP谓词方法;它的 对于任何其他方法,行为未定义。这个装饰者没有 使方法异步;它告诉框架该方法是 异步的。
因此,您无法将其用于on_message
和ready_finish
,请将其删除。
对于on_message
和ready_finish
,如果您有任何异步调用,则可以使用@tornado.gen.coroutine
。
答案 2 :(得分:0)
此装饰器应仅应用于HTTP谓词方法;其行为未定义任何其他方法。这个装饰器不会使方法异步;它告诉框架该方法是异步的。为了使这个装饰器有用,该方法必须(至少有时)做一些异步的事情。