我设法编写了一个相当愚蠢的bug,它会让我的一个请求处理程序运行一个非常慢的数据库查询.
有趣的一点是,我注意到即使很长时间围攻完成龙卷风仍然在通过请求(有时90年后)搅拌.(评论 - >我不是100%确定Siege的工作方式,但我很确定它关闭了连接..)
我的问题分为两部分: - 当客户端关闭连接时,Tornado会取消请求处理程序吗? - 有没有办法在Tornado中超时请求处理程序?
我通读了代码,似乎无法找到任何东西.即使我的请求处理程序在上面的错误中异步运行,待处理请求的数量也会增加到应用程序速度变慢的水平,最好关闭连接.
当客户端断开连接时,Tornado不会自动关闭请求处理程序.但是,您可以覆盖on_connection_close以在客户端丢弃时收到警报,这将允许您取消您的连接.可以使用上下文管理器(或装饰器)来处理设置超时以处理请求; 用于tornado.ioloop.IOLoop.add_timeout调度某个方法,该方法将请求timeout作为__enter__上下文管理器的一部分运行,然后__exit__在上下文管理器的块中取消该回调.这是一个展示这两个想法的例子:
import time
import contextlib
from tornado.ioloop import IOLoop
import tornado.web
from tornado import gen
@gen.coroutine
def async_sleep(timeout):
yield gen.Task(IOLoop.instance().add_timeout, time.time() + timeout)
@contextlib.contextmanager
def auto_timeout(self, timeout=2): # Seconds
handle = IOLoop.instance().add_timeout(time.time() + timeout, self.timed_out)
try:
yield handle
except Exception as e:
print("Caught %s" % e)
finally:
IOLoop.instance().remove_timeout(handle)
if not self._timed_out:
self.finish()
else:
raise Exception("Request timed out") # Don't continue on passed this point
class TimeoutableHandler(tornado.web.RequestHandler):
def initialize(self):
self._timed_out = False
def timed_out(self):
self._timed_out = True
self.write("Request timed out!\n")
self.finish() # Connection to client closes here.
# You might want to do other clean up here.
class MainHandler(TimeoutableHandler):
@gen.coroutine
def get(self):
with auto_timeout(self): # We'll timeout after 2 seconds spent in this block.
self.sleeper = async_sleep(5)
yield self.sleeper
print("writing") # get will abort before we reach here if we timed out.
self.write("hey\n")
def on_connection_close(self):
# This isn't the greatest way to cancel a future, since it will not actually
# stop the work being done asynchronously. You'll need to cancel that some
# other way. Should be pretty straightforward with a DB connection (close
# the cursor/connection, maybe?)
self.sleeper.set_exception(Exception("cancelled"))
application = tornado.web.Application([
(r"/test", MainHandler),
])
application.listen(8888)
IOLoop.instance().start()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6018 次 |
| 最近记录: |