mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-05-03 03:24:51 -04:00
Update to use new timeout function everywhere.
The existing deferred timeout helper function (and the one into twisted) suffer from a bug when a deferred's canceller throws an exception, #3842. The new helper function doesn't suffer from this problem.
This commit is contained in:
parent
05b9937cd7
commit
a334e1cace
4 changed files with 43 additions and 72 deletions
|
@ -380,23 +380,25 @@ class DeferredTimeoutError(Exception):
|
|||
"""
|
||||
|
||||
|
||||
def add_timeout_to_deferred(deferred, timeout, reactor, on_timeout_cancel=None):
|
||||
"""
|
||||
Add a timeout to a deferred by scheduling it to be cancelled after
|
||||
timeout seconds.
|
||||
def _cancelled_to_timed_out_error(value, timeout):
|
||||
if isinstance(value, failure.Failure):
|
||||
value.trap(CancelledError)
|
||||
raise DeferredTimeoutError(timeout, "Deferred")
|
||||
return value
|
||||
|
||||
This is essentially a backport of deferred.addTimeout, which was introduced
|
||||
in twisted 16.5.
|
||||
|
||||
If the deferred gets timed out, it errbacks with a DeferredTimeoutError,
|
||||
unless a cancelable function was passed to its initialization or unless
|
||||
a different on_timeout_cancel callable is provided.
|
||||
def timeout_deferred(deferred, timeout, reactor, on_timeout_cancel=None):
|
||||
"""The in built twisted `Deferred.addTimeout` fails to time out deferreds
|
||||
that have a canceller that throws exceptions. This method creates a new
|
||||
deferred that wraps and times out the given deferred, correctly handling
|
||||
the case where the given deferred's canceller throws.
|
||||
|
||||
NOTE: Unlike `Deferred.addTimeout`, this function returns a new deferred
|
||||
|
||||
Args:
|
||||
deferred (defer.Deferred): deferred to be timed out
|
||||
timeout (Number): seconds to time out after
|
||||
reactor (twisted.internet.reactor): the Twisted reactor to use
|
||||
|
||||
deferred (Deferred)
|
||||
timeout (float): Timeout in seconds
|
||||
reactor (twisted.internet.reactor): The twisted reactor to use
|
||||
on_timeout_cancel (callable): A callable which is called immediately
|
||||
after the deferred times out, and not if this deferred is
|
||||
otherwise cancelled before the timeout.
|
||||
|
@ -407,47 +409,9 @@ def add_timeout_to_deferred(deferred, timeout, reactor, on_timeout_cancel=None):
|
|||
|
||||
The default callable (if none is provided) will translate a
|
||||
CancelledError Failure into a DeferredTimeoutError.
|
||||
"""
|
||||
timed_out = [False]
|
||||
|
||||
def time_it_out():
|
||||
timed_out[0] = True
|
||||
deferred.cancel()
|
||||
|
||||
delayed_call = reactor.callLater(timeout, time_it_out)
|
||||
|
||||
def convert_cancelled(value):
|
||||
if timed_out[0]:
|
||||
to_call = on_timeout_cancel or _cancelled_to_timed_out_error
|
||||
return to_call(value, timeout)
|
||||
return value
|
||||
|
||||
deferred.addBoth(convert_cancelled)
|
||||
|
||||
def cancel_timeout(result):
|
||||
# stop the pending call to cancel the deferred if it's been fired
|
||||
if delayed_call.active():
|
||||
delayed_call.cancel()
|
||||
return result
|
||||
|
||||
deferred.addBoth(cancel_timeout)
|
||||
|
||||
|
||||
def _cancelled_to_timed_out_error(value, timeout):
|
||||
if isinstance(value, failure.Failure):
|
||||
value.trap(CancelledError)
|
||||
raise DeferredTimeoutError(timeout, "Deferred")
|
||||
return value
|
||||
|
||||
|
||||
def timeout_no_seriously(deferred, timeout, reactor):
|
||||
"""The in build twisted deferred addTimeout (and the method above)
|
||||
completely fail to time things out under some unknown circumstances.
|
||||
|
||||
Lets try a different way of timing things out and maybe that will make
|
||||
things work?!
|
||||
|
||||
TODO: Kill this with fire.
|
||||
Returns:
|
||||
Deferred
|
||||
"""
|
||||
|
||||
new_d = defer.Deferred()
|
||||
|
@ -466,7 +430,8 @@ def timeout_no_seriously(deferred, timeout, reactor):
|
|||
|
||||
def convert_cancelled(value):
|
||||
if timed_out[0]:
|
||||
return _cancelled_to_timed_out_error(value, timeout)
|
||||
to_call = on_timeout_cancel or _cancelled_to_timed_out_error
|
||||
return to_call(value, timeout)
|
||||
return value
|
||||
|
||||
deferred.addBoth(convert_cancelled)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue