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 <seanq@element.io>
This commit is contained in:
Sean Quah 2022-05-10 20:39:05 +01:00 committed by GitHub
parent 29f06704b8
commit c997bfb926
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 9 additions and 5 deletions

1
changelog.d/12694.misc Normal file
View File

@ -0,0 +1 @@
Capture the `Deferred` for request cancellation in `_AsyncResource`.

View File

@ -344,7 +344,9 @@ class _AsyncResource(resource.Resource, metaclass=abc.ABCMeta):
def render(self, request: SynapseRequest) -> int: def render(self, request: SynapseRequest) -> int:
"""This gets called by twisted every time someone sends us a request.""" """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 return NOT_DONE_YET
@wrap_async_request_handler @wrap_async_request_handler

View File

@ -92,11 +92,12 @@ class SynapseRequest(Request):
# we can't yet create the logcontext, as we don't know the method. # we can't yet create the logcontext, as we don't know the method.
self.logcontext: Optional[LoggingContext] = None self.logcontext: Optional[LoggingContext] = None
# The `Deferred` to cancel if the client disconnects early. Expected to be set # The `Deferred` to cancel if the client disconnects early and
# by `Resource.render`. # `is_render_cancellable` is set. Expected to be set by `Resource.render`.
self.render_deferred: Optional["Deferred[None]"] = None self.render_deferred: Optional["Deferred[None]"] = None
# A boolean indicating whether `_render_deferred` should be cancelled if the # A boolean indicating whether `render_deferred` should be cancelled if the
# client disconnects early. Expected to be set during `Resource.render`. # client disconnects early. Expected to be set by the coroutine started by
# `Resource.render`, if rendering is asynchronous.
self.is_render_cancellable = False self.is_render_cancellable = False
global _next_request_seq global _next_request_seq