Tuesday, November 20, 2012

Cancelling Deferreds

Deferreds are Twisted's abstraction for result callbacks, encapsulating the result of some asynchronous task. For example, the result of retrieving a web page:
d = getPage("http://www.example.com/")
d.addCallback(gotPage)
d.addErrback(errorHandler)
What if you wanted to cancel that page download? Perhaps the user hit the cancel button in the application GUI because things were taking too long. To do this, you can call the Deferred's cancel() method:
download = getPage("http://www.example.com/")
# Open a dialog that lets the user cancel the download:
dialog = ModalDialog(message="Downloading...", button="Cancel",
                     onClick=download.cancel)
download.addCallback(dialog.close)
Cancellation of Deferreds is best effort, which is to say it may not actually cancel the underlying operation. This may be the case for a number of reasons:
  1. The Deferred doesn't know how to cancel the underlying operation.
  2. The underlying operation may have reached an uncancellable state, because some irreversible operation has been done.
  3. The Deferred may already have a result, and so there's nothing to cancel.
Calling cancel() will always succeed without an error regardless of whether or not cancellation was possible. In cases 1 and 2 the Deferred may well errback with a twisted.internet.defer.CancelledError while the underlying operation continues. Deferreds that support cancellation should document what they do when cancelled, if they are uncancellable in certain edge cases, etc..

That's cancellation from the point of view of the caller. In my next posting I will explain how the creator of the Deferred can make cancellation actually do something, e.g. stop an in-progress page download.

No comments:

Post a Comment