[Twisted-Python] parallel callbacks? Or inserting into the callback chain?

Lenny G Arbage alengarbage at yahoo.com
Fri Jan 27 22:23:50 EST 2006

Is there any way to make a deferred call its callbacks
'in parallel,' or to insert a callback into the
callback chain at a point further up than the end?  Or
maybe there is some other pattern for doing what I
need to accomplish, which is getting the result from a
deferred before it gets modified by the return of
other callbacks that have already been added, but
before it is fired.

Here is an example that illustrates why I need
something like this.  It is almost identical to the
first example in the deferred howto

from twisted.internet import reactor, defer

pending = {}

def getDummyData(queryName, x):
    if pending.has_key(x):
        print "%s piggybacking on pending big
expensive query" 
            % queryName
        return pending[x]

    d = defer.Deferred()
    # simulate a delayed result by asking the reactor
to fire the
    # Deferred in 2 seconds time with the result x*3
    print "%s about to do some big expensive query" %
    reactor.callLater(2, d.callback, x*3)
    pending[x] = d
    return d

def printData(d, queryName):
    Data handling function to be added as a callback:
handles the
    data by printing the result
    print "%s received: %s" % (queryName, d)

# simulate two calls (originating from some client[s])
at roughly the same
# time for the same query.
d = getDummyData('query1',3)
d = getDummyData('query2',3)

# manually set up the end of the process by asking the
reactor to
# stop itself in 13 seconds time
reactor.callLater(4, reactor.stop)
# start up the Twisted reactor (event loop handler)

The output, as you might expect, looks like this:

query1 about to do some big expensive query thing
query2 piggybacking on pending big expensive query
query1 received: 9
query2 received: None

I'd like the output for query2 to match that of

Of course, this could be accomplished by adding a
'return d' to the end of printData(), but this is not
feasible in this case, because the caller of
getDummyData() might have added his own callbacks (in
addition to printData()) that do whatever it is that
he desires, including changing the return result or
not propogating it up the chain.

In the scenario I am designing for, getDummyData()
will be invoked by client(s), and we don't want to
open up new "big expensive" queries to the source if
one is already pending that matches.  Thus, I'd love
for getDummyData() to return a deferred that
piggybacks on an existing query, if one that matches
is still pending.

Can this be done?  Is there a way to modify the above
[simple] example so that it performs this behavior? 
Is there some other way to approach the problem that
I'm missing?

Lenny G.

Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 

More information about the Twisted-Python mailing list