[PEAK] StopIteration: Unexpected reactor exit

John Landahl john at landahl.org
Thu Mar 25 22:59:52 EST 2004


On Thu, 25 Mar 2004 19:35:56 -0500, Phillip J. Eby <pje at telecommunity.com> 
wrote:
> Only because you're using Twisted for both levels of event loop.  PEAK 
> allows you to have as many event loops as you like, but Twisted supports 
> only one.

By this do you mean that there can be only one EventLoop instance per 
application (which is the case in my app; it uses 
"binding.Obtain(events.IEventLoop)"), or one active call to that 
instance's runUntil()?

Some further information gathering has revealed that the reactor does not 
get stopped until the Task in question next tries to yield.  All interim 
EventLoop.runUntil() invocations cause no problems.  In fact, if I change 
the yields in the Task to eventLoop.runUntil() calls, the problem does not 
occur.

So to be a little more specific:

    Task A
      Creates a new Task B
        Runs a method on object C (func1)
          calls func2 (indirectly)
            calls reactor.spawnProcess(), waits for completion with 
runUntil()
            calls a remote PB method, waits for completion with runUntil()
            returns data
          data is used to setup another spawnProcess()
        yields on a deferred returned by C
        processes data from the deferred
        reports results via a PB call

Immediately after this yield, the runUntil() called by 
EventDriven.mainLoop raises StopIteration.  Using runUntil() here instead 
of yield does not cause the StopIteration.  Could there be something in 
the Task class that causes B to end prematurely?

FWIW, the Twisted reactor's mainloop ends directly after the return on 
line 462 of peak.events.event_threads.py, followed by the early demise of 
EventDriven.mainLoop.eventLoop.runUntil().  Not knowing what calls 
Task.step(), I'm not sure how to trace what happens between the return and 
the end of the reactor's mainloop.

> You'll have to make the synchronous functions asynchronous then.  What 
> you do is take all the 100% synchronous parts (i.e. parts that *don't* 
> call any asynchronous code), and farm them out to threads using 
> reactor.deferToThread.  You'll then be left with a 100% asynchronous 
> task.

I don't know if it's possible to refactor it this way since the data func2 
returns to its caller is dependent on the two Twisted deferreds.  One 
possibility might be to have these run in the main thread through 
callFromThread(), but that might be difficult in this scenario.  I'll look 
into this option further.



More information about the PEAK mailing list