In my last post I talked about the motivation for cancellation, and how one cancels a Deferred. In this post I'm going to explain how to make a Deferred created by your code do something useful when cancelled.
Let's imagine you are implementing an HTTP client, which returns a Deferred firing with the response from the server. Cancellation is best achieved by closing the connection. In order to make cancellation do that, all you have to do is pass a function to the constructor of the Deferred (it will get called with the Deferred that is being cancelled):
Now if someone callsclass HTTPClient(Protocol): def request(self, method, path): self.resultDeferred = Deferred( lambda ignore: self.transport.abortConnection()) request = b"%s %s HTTP/1.0\r\n\r\n" % (method, path) self.transport.write(request) return self.resultDeferred def dataReceived(self, data): # ... parse HTTP response ... # ... eventually call self.resultDeferred.callback() ...
cancel()on the Deferred returned from
HTTPClient.request(), the HTTP request will be cancelled (assuming it's not too late to do so). Care should be taken not to
callback()a Deferred that has already been cancelled.
As you can see, making your Deferreds cancellable is fairly simple, and the benefits are great: the ability to cancel an operation half-way in a standard manner, freeing up resources that no longer need to be used. In addition, as we will see in my next post, cancellation can be used as the basis for adding timeouts to Deferreds.