diff options
author | Sean Quah <8349537+squahtx@users.noreply.github.com> | 2022-05-10 14:06:08 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-10 14:06:08 +0100 |
commit | 5cfb0045955f8b5e9e8a1e0505fa2b5ed4f7bde2 (patch) | |
tree | 32d89a41bca41d3a1f689be4597440b01f42d53e /synapse | |
parent | Add `@cancellable` decorator, for use on request handlers (#12586) (diff) | |
download | synapse-5cfb0045955f8b5e9e8a1e0505fa2b5ed4f7bde2.tar.xz |
Add ability to cancel disconnected requests to `SynapseRequest` (#12588)
Signed-off-by: Sean Quah <seanq@element.io>
Diffstat (limited to 'synapse')
-rw-r--r-- | synapse/http/site.py | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/synapse/http/site.py b/synapse/http/site.py index 0b85a57d77..f7f1c57042 100644 --- a/synapse/http/site.py +++ b/synapse/http/site.py @@ -19,6 +19,7 @@ from typing import TYPE_CHECKING, Any, Generator, Optional, Tuple, Union import attr from zope.interface import implementer +from twisted.internet.defer import Deferred from twisted.internet.interfaces import IAddress, IReactorTime from twisted.python.failure import Failure from twisted.web.http import HTTPChannel @@ -91,6 +92,13 @@ 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`. + 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`. + self.is_render_cancellable = False + global _next_request_seq self.request_seq = _next_request_seq _next_request_seq += 1 @@ -357,7 +365,21 @@ class SynapseRequest(Request): {"event": "client connection lost", "reason": str(reason.value)} ) - if not self._is_processing: + if self._is_processing: + if self.is_render_cancellable: + if self.render_deferred is not None: + # Throw a cancellation into the request processing, in the hope + # that it will finish up sooner than it normally would. + # The `self.processing()` context manager will call + # `_finished_processing()` when done. + with PreserveLoggingContext(): + self.render_deferred.cancel() + else: + logger.error( + "Connection from client lost, but have no Deferred to " + "cancel even though the request is marked as cancellable." + ) + else: self._finished_processing() def _started_processing(self, servlet_name: str) -> None: |