[Twisted-Python] using a reactor in a loop

Jean-Paul Calderone exarkun at divmod.com
Thu Mar 1 16:48:41 EST 2007

On Thu, 1 Mar 2007 13:28:04 -0800, Tom Brown <brown at esteem.com> wrote:
>On Thursday 01 March 2007 09:32, Jean-Paul Calderone wrote:
>> On Thu, 1 Mar 2007 09:21:50 -0800, Tom Brown <brown at esteem.com> wrote:
>> >Hello,
>> >
>> >I am trying to use a reactor in a loop. The application will go through
>> > the loop twice then hang when trying to stop the protocol. Here's my
>> > loop:
>> >
>> > [snip]
>> >
>> >I see the 'reactor stopped' get printed out twice through the loop but I
>> > don't see 'running server' get printed out a third time. So,
>> > reactor.run() is not returning. I must be missing something or going at
>> > this completely wrong. Any suggestions?
>> The simple thing you're missing is that reactors can't be restarted. :)
>> One way you can restructure your program to avoid needing to do this is to
>> put the body of your loop (minus reactor.run()) into a function which
>> returns a Deferred and to replace the call to reactor.stop() with code
>> which fires that Deferred.  You can set up callbacks on this Deferred to
>> execute the whole thing again if necessary.
>I read through the deferreds documentation and I'm thoroughly confused on how
>to set this up. I tried to simplify the problem with a simple function:
>In [60]: def foo():
>   ....:     print 'foo'
>   ....:     return Deferred()
>   ....:
>In [61]: d = foo()
>In [62]: d.addCallback(foo)
>Out[62]: <Deferred at 0xb786792cL>
>So, now I'm lost as to what to do from here. Any suggestions would be

Something needs to call that Deferred back for anything further to happen
(though what will happen next is a TypeError, since the callback, `foo',
doesn't accept any arguments, and all Deferred callbacks need to accept at
least one argument. ;)

For example:

   >>> def foo(result):
   ...     print 'Got a result:', result
   >>> d = Deferred()
   >>> d.addCallback(foo)
   <Deferred at 0xB7D26F4CL>
   >>> d.callback("Hello, world")
   Got a result: Hello, world

Or to set up a (terrible, infinite, actually-infinitely-recursive) loop:

   >>> def bar(lastResult=None):
   ...     print 'Previous result was:', lastResult
   ...     d = Deferred()
   ...     d.addCallback(bar)
   ...     d.callback(str(lastResult) + "bar")

(Slightly) More realistically, you might have something like this:

   >>> class NoOp(Protocol):
   ...     def __init__(self, onConnect):
   ...             self.onConnect = onConnect
   ...     def connectionMade(self):
   ...             self.transport.loseConnection()
   ...             self.onConnect.callback(None)
   >>> def baz(ignored=None):
   ...     d = Deferred()
   ...     p = NoOp(d)
   ...     f = ClientFactory()
   ...     f.protocol = lambda: p
   ...     reactor.connectTCP(host, port, f)
   ...     d.addCallback(baz)

Which is similar to the previous example, in that it sets up a loop with
a Deferred for an asynchronous operation (connecting to a remote host),
but won't lead to infinite recursion, and might actually resemble what you
want to do. :)


More information about the Twisted-Python mailing list