public final class Deferred<T> extends Object
A thread-safeimplementation of a deferred result for easy asynchronous processing.
Thisimplementation is based on Twisted's Python Deferred
API.
This API is a simple and elegant way ofmanaging asynchronous and dynamic "pipelines" (processing chains)without having to explicitly define a finite state machine.
The tl;dr version
We're all busy and don't always have timeto RTFM in details. Please pay special attention to theinvariants youmust respect. Other than that, here's an executive summary of whatDeferred
offers:
- A
Deferred
is like aFuture
with a dynamicCallback
chain associated to it. - When the deferred result becomes available, the callback chain gets triggered.
- The result of one callback in the chain is passed on to the next.
- When a callback returns another
Deferred
, the next callback in the chain doesn't get executed until that otherDeferred
result becomes available. - There are actually two callback chains. One is for normal processing, the other is for error handling / recovery. A
Callback
that handles errors is called an "errback". Deferred
is an important building block for writing easy-to-use asynchronous APIs in a thread-safe fashion.
Understanding the concept of Deferred
The idea is that a Deferred
represents a result that's not yet available. An asynchronous operation (I/O,RPC, whatever) has been started and will hand its result (be it successful ornot) to theDeferred
inthe future. The key difference between a Deferred
and aFuture
isthat a Deferred
has acallback chain associated to it, whereas withjust aFuture
youneed get the result manually at some point, which poses problems such as: Howdo you know when the result is available? What if the result itself depends onanother future?
When you start anasynchronous operation, you typically want to be called back when the operationcompletes. If the operation was successful, you want your callback to use itsresult to carry on what you were doing at the time you started the asynchronousoperation. If there was an error, you want to trigger some error handling code.
But there's moreto a Deferred
than a single callback. You can addarbitrary number of callbacks, which effectively allows you to easily buildcomplex processing pipelines in a really simple and elegant way.
Understanding the callback chain
Let's take a typical example. You'rewriting a client library for others to use your simple remote storage service.When your users call theget
method in your library, you want toretrieve some piece of data from your remote service and hand it back to theuser, but you want to do so in an asynchronous fashion.
When the user ofyour client library invokes get
, you assemble arequest and send it out to the remote server through a socket. Before sendingit to the socket, you create aDeferred
and you store itsomewhere, for example in a map, to keep an association between the request andthisDeferred
. You then return this Deferred
to the user, this is how they will access the deferred result as soon as theRPC completes.
Sooner or later,the RPC will complete (successfully or not), and your socket will becomereadable (or maybe closed, in the event of a failur