From: Konstantin Kopachev Date: Fri, 10 Nov 2017 05:19:42 +0000 (-0800) Subject: Break circular references when async request handler raises exception X-Git-Tag: v5.0.0~41^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e266a318b82a6508bfca1fec770df6a8bf68507;p=thirdparty%2Ftornado.git Break circular references when async request handler raises exception --- diff --git a/maint/circlerefs/circlerefs.py b/maint/circlerefs/circlerefs.py index 0fb59c6f9..fe91a09b4 100644 --- a/maint/circlerefs/circlerefs.py +++ b/maint/circlerefs/circlerefs.py @@ -70,8 +70,16 @@ class DummyHandler(web.RequestHandler): self.write('ok\n') +class DummyAsyncHandler(web.RequestHandler): + @gen.coroutine + def get(self): + raise web.Finish('ok\n') + + + application = web.Application([ (r'/dummy/', DummyHandler), + (r'/dummyasync/', DummyAsyncHandler), (r'/collect/', CollectHandler), ], debug=True) @@ -90,11 +98,12 @@ def main(): # poke at it with a browser. client = httpclient.AsyncHTTPClient() yield client.fetch('http://127.0.0.1:8888/dummy/') + yield client.fetch('http://127.0.0.1:8888/dummyasync/', raise_error=False) # Now report on the results. - gc.collect() resp = yield client.fetch('http://127.0.0.1:8888/collect/') print(resp.body) + if __name__ == "__main__": ioloop.IOLoop.current().run_sync(main) diff --git a/tornado/gen.py b/tornado/gen.py index 533ccb749..b56b0efd9 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -290,7 +290,11 @@ def _make_coroutine_wrapper(func, replace_callback): result = _value_from_stopiteration(e) except Exception: future_set_exc_info(future, sys.exc_info()) - return future + try: + return future + finally: + # Avoid circular references + future = None else: if isinstance(result, GeneratorType): # Inline the first iteration of Runner.run. This lets us diff --git a/tornado/web.py b/tornado/web.py index 0cc34b8e4..f2749f7c4 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -1537,6 +1537,9 @@ class RequestHandler(object): self._handle_request_exception(e) except Exception: app_log.error("Exception in exception handler", exc_info=True) + finally: + # Unset result to avoid circular references + result = None if (self._prepared_future is not None and not self._prepared_future.done()): # In case we failed before setting _prepared_future, do it