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 import attr
from zope.interface import implementer from zope.interface import implementer
from twisted.internet.defer import Deferred
from twisted.internet.interfaces import IAddress, IReactorTime from twisted.internet.interfaces import IAddress, IReactorTime
from twisted.python.failure import Failure from twisted.python.failure import Failure
from twisted.web.http import HTTPChannel 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. # 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
# 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 global _next_request_seq
self.request_seq = _next_request_seq self.request_seq = _next_request_seq
_next_request_seq += 1 _next_request_seq += 1
@ -357,7 +365,21 @@ class SynapseRequest(Request):
{"event": "client connection lost", "reason": str(reason.value)} {"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() self._finished_processing()
def _started_processing(self, servlet_name: str) -> None: def _started_processing(self, servlet_name: str) -> None: