What is a recommended practice for handling a timeout that was set for a Twisted operation that finished successfully before the timeout expired?
Should the timeout be left running and depend on the Deferred.cancel()
method having no effect on a finished Deferred?
Or is it better to explicitly cancel the timeout when the operation finishes?
The second option seems cleaner, but requires more complex and error-prone code (it is easy to leave a running timer, especially for operations that require several steps).
Maybe the best thing would be to add a timeout-cancelling callback to the deferred in the same place where you set the timeout.
from twisted.internet import reactor, task
def foo():
return 'done'
def somethingPossiblyCanceled():
return task.deferLater(reactor, 1, foo)
def addTimeout(d, duration):
timeout = reactor.callLater(duration, d.cancel)
def cancelTimeout(result):
if timeout.active():
timeout.cancel()
print('(timeout canceled)')
return result
d.addBoth(cancelTimeout)
def main():
d = somethingPossiblyCanceled()
addTimeout(d, 2)
def finished(result):
print(result)
reactor.stop()
def canceled(failure):
print('timed out: {0}'.format(failure))
reactor.stop()
d.addCallbacks(finished, canceled)
reactor.callWhenRunning(main)
reactor.run()