[Twisted-Python] using a reactor in a loop

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: def main(): factory = Factory() factory.numProtocols = 0 factory.protocol = AqapProtocol while True: print 'running server' # do other work ... reactor.listenTCP(48555, factory) reactor.run() # stopped by protocol Here's how the protocol stops the reactor: def connectionLost(self, reason): self.factory.numProtocols -= 1 if not self.factory.numProtocols: print 'stopping reactor' reactor.stop() print 'reactor stopped' 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? Thanks, Tom

On Thu, 1 Mar 2007 09:21:50 -0800, Tom Brown <brown@esteem.com> wrote:
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. Jean-Paul

On Thursday 01 March 2007 09:32, Jean-Paul Calderone wrote:
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() 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 appreciated. Thanks, Tom

On Thu, 1 Mar 2007 13:28:04 -0800, Tom Brown <brown@esteem.com> wrote:
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:
Or to set up a (terrible, infinite, actually-infinitely-recursive) loop:
(Slightly) More realistically, you might have something like this:
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. :) Jean-Paul

Hi Tom, On Thu, 01 Mar 2007 11:21:50 -0600, Tom Brown <brown@esteem.com> wrote:
The reactor provides an event loop already, so I am confused as to why you are trying to run it inside another loop. Based on the code you have posted here, I can't ascertain what your goal is. Generally speaking, you'd be better served by using the reactor's loop instead of your own, and stopping/starting your listeners, rather than the reactor itself. Also, stopping the reactor from within a protocol is probably not ideal. That's sort of like telling your OS to shut down when you're done saving a file ;) Hope this helps, L. Daniel Burr

On Thursday 01 March 2007 09:42, L. Daniel Burr wrote:
Thanks for your reply. My goal is this: 1) do specific tasks 2) run the server and wait for a connection 3) when a connection is made, do tasks as instructed by the client in the AqapProtocol code. 4) when connection is lost, close server and go back to 1) Shutting down the server is not necessary if I could get past the reactor.run(). A previous post suggested I use deferreds. So, that is probably what I need to. I just need to learn how to use them. Thanks, Tom

Tom Brown wrote:
There's really good documentation about twisted and its event-driven programming model, there you'll find what you're looking for. in twisted you never "get past" the reactor.run() (until you quit the application), everything is done inside its loop. so when using twisted you should rather consider this: 1) run the event-loop 2) do specific tasks (if you need to complete long running tasks, you could use deferToThread or a pool of threads, to keep your event-loop responsive ) 3) setup listener for connections (now you have your server) 4) when a connection is made, do tasks as instructed by the client in the AqapProtocol code. 5) if really necessary, stop listening for/refuse connections without stopping the eventloop, but maybe it's better to return a "service suspended, come back later" kind of message 6) goto 2) AFAIK twisted doesn't support restarting the reactor, there're some issues with cleaning up the state. But when you get used to it, you'll never feel the need to do that anyway, which might be the main reason why it's neither supported nor really discussed. You can do anything you want while the reactor is running. Johann

On Thu, 1 Mar 2007 09:21:50 -0800, Tom Brown <brown@esteem.com> wrote:
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. Jean-Paul

On Thursday 01 March 2007 09:32, Jean-Paul Calderone wrote:
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() 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 appreciated. Thanks, Tom

On Thu, 1 Mar 2007 13:28:04 -0800, Tom Brown <brown@esteem.com> wrote:
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:
Or to set up a (terrible, infinite, actually-infinitely-recursive) loop:
(Slightly) More realistically, you might have something like this:
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. :) Jean-Paul

Hi Tom, On Thu, 01 Mar 2007 11:21:50 -0600, Tom Brown <brown@esteem.com> wrote:
The reactor provides an event loop already, so I am confused as to why you are trying to run it inside another loop. Based on the code you have posted here, I can't ascertain what your goal is. Generally speaking, you'd be better served by using the reactor's loop instead of your own, and stopping/starting your listeners, rather than the reactor itself. Also, stopping the reactor from within a protocol is probably not ideal. That's sort of like telling your OS to shut down when you're done saving a file ;) Hope this helps, L. Daniel Burr

On Thursday 01 March 2007 09:42, L. Daniel Burr wrote:
Thanks for your reply. My goal is this: 1) do specific tasks 2) run the server and wait for a connection 3) when a connection is made, do tasks as instructed by the client in the AqapProtocol code. 4) when connection is lost, close server and go back to 1) Shutting down the server is not necessary if I could get past the reactor.run(). A previous post suggested I use deferreds. So, that is probably what I need to. I just need to learn how to use them. Thanks, Tom

Tom Brown wrote:
There's really good documentation about twisted and its event-driven programming model, there you'll find what you're looking for. in twisted you never "get past" the reactor.run() (until you quit the application), everything is done inside its loop. so when using twisted you should rather consider this: 1) run the event-loop 2) do specific tasks (if you need to complete long running tasks, you could use deferToThread or a pool of threads, to keep your event-loop responsive ) 3) setup listener for connections (now you have your server) 4) when a connection is made, do tasks as instructed by the client in the AqapProtocol code. 5) if really necessary, stop listening for/refuse connections without stopping the eventloop, but maybe it's better to return a "service suspended, come back later" kind of message 6) goto 2) AFAIK twisted doesn't support restarting the reactor, there're some issues with cleaning up the state. But when you get used to it, you'll never feel the need to do that anyway, which might be the main reason why it's neither supported nor really discussed. You can do anything you want while the reactor is running. Johann
participants (4)
-
Jean-Paul Calderone
-
Johann Borck
-
L. Daniel Burr
-
Tom Brown