Add ability to cancel disconnected requests to SynapseRequest (#12588)

Signed-off-by: Sean Quah <seanq@element.io>
This commit is contained in:
Sean Quah 2022-05-10 14:06:08 +01:00 committed by GitHub
parent 5c00151c28
commit 5cfb004595
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 1 deletions

1
changelog.d/12588.misc Normal file
View file

@ -0,0 +1 @@
Add ability to cancel disconnected requests to `SynapseRequest`.

View file

@ -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: