From c997bfb926a29f0ec894fca889cc5eae603f4027 Mon Sep 17 00:00:00 2001 From: Sean Quah <8349537+squahtx@users.noreply.github.com> Date: Tue, 10 May 2022 20:39:05 +0100 Subject: [PATCH] Capture the `Deferred` for request cancellation in `_AsyncResource` (#12694) All async request processing goes through `_AsyncResource`, so this is the only place where a `Deferred` needs to be captured for cancellation. Unfortunately, the same isn't true for determining whether a request can be cancelled. Each of `RestServlet`, `BaseFederationServlet`, `DirectServe{Html,Json}Resource` and `ReplicationEndpoint` have different wrappers around the method doing the request handling and they all need to be handled separately. Signed-off-by: Sean Quah --- changelog.d/12694.misc | 1 + synapse/http/server.py | 4 +++- synapse/http/site.py | 9 +++++---- 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 changelog.d/12694.misc diff --git a/changelog.d/12694.misc b/changelog.d/12694.misc new file mode 100644 index 0000000000..e1e956a513 --- /dev/null +++ b/changelog.d/12694.misc @@ -0,0 +1 @@ +Capture the `Deferred` for request cancellation in `_AsyncResource`. diff --git a/synapse/http/server.py b/synapse/http/server.py index 8c96f2196e..4b4debc5cd 100644 --- a/synapse/http/server.py +++ b/synapse/http/server.py @@ -344,7 +344,9 @@ class _AsyncResource(resource.Resource, metaclass=abc.ABCMeta): def render(self, request: SynapseRequest) -> int: """This gets called by twisted every time someone sends us a request.""" - defer.ensureDeferred(self._async_render_wrapper(request)) + request.render_deferred = defer.ensureDeferred( + self._async_render_wrapper(request) + ) return NOT_DONE_YET @wrap_async_request_handler diff --git a/synapse/http/site.py b/synapse/http/site.py index f7f1c57042..eeec74b78a 100644 --- a/synapse/http/site.py +++ b/synapse/http/site.py @@ -92,11 +92,12 @@ class SynapseRequest(Request): # we can't yet create the logcontext, as we don't know the method. self.logcontext: Optional[LoggingContext] = None - # The `Deferred` to cancel if the client disconnects early. Expected to be set - # by `Resource.render`. + # The `Deferred` to cancel if the client disconnects early and + # `is_render_cancellable` is set. Expected to be set by `Resource.render`. self.render_deferred: Optional["Deferred[None]"] = None - # A boolean indicating whether `_render_deferred` should be cancelled if the - # client disconnects early. Expected to be set during `Resource.render`. + # A boolean indicating whether `render_deferred` should be cancelled if the + # client disconnects early. Expected to be set by the coroutine started by + # `Resource.render`, if rendering is asynchronous. self.is_render_cancellable = False global _next_request_seq