@ -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.
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
NOTE : Unlike ` Deferred . addTimeout ` , this function returns a new deferred
Args :
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 )