[Twisted-Python] The Trial of the DirtyReactorError
Jean-Paul Calderone
exarkun at divmod.com
Fri Apr 13 09:22:05 MDT 2007
On Fri, 13 Apr 2007 10:15:28 +0100, Matthew Glubb <matt at zgroupplc.com> wrote:
>-----BEGIN PGP SIGNED MESSAGE-----
>Hash: SHA1
>
>Hi All,
>
>Following on from my DirtyReactorError errors whilst running unit tests
>under trial I opted, as glyph suggested, to call listenTCP inside the
>ServerFactory in order to keep track of the port and shut it down cleanly.
>
>On 12 Apr 2007, at 19:56, glyph at divmod.com wrote:
>>If they are "always shut down", what event currently shuts them down? Have
>>your test trigger that event. If they're one-shot, then perhaps the
>>method that calls listenTCP should be on the factory itself, making it
>>even easier to keep track of the Port instance it is associated with.
>
>This causes me a problem. When a client connection is lost, I want to
>shutdown the server. The only way that I can see to do this is by the
>connectionLost event calling a method in my ServerFactory that shuts down
>the listening port:
>
>class Echo(basic.LineOnlyReceiver):
>
> def connectionLost(self, reason):
> self.factory.shutdown(reason)
>
>class EchoServerFactory(protocol.ServerFactory):
> protocol = Echo
> port = None
>
> def __init__(self, port):
> self.port = reactor.listenTCP(port, self)
>
> def shutdown(self, reason):
> self.port.stopListening()
>
>*However*, this results in the following error:
>
>twisted.trial.util.PendingTimedCallsError: pendingTimedCalls still pending
>(consider setting twisted.internet.base.DelayedCall.debug = True):
><DelayedCall 24706704 [-0.00161504745483s] called=0 cancelled=0
>Port.connectionLost(<twisted.python.failure.Failure <class
>'twisted.internet.error.ConnectionDone'>>)
>
>Obviously, tcp.Port.stopListening() results in the Echo.connectionLost
>event being triggered, which in turn calls EchoServerFactory.shutdown(),
>which triggers an additional Echo.connectionLost event. It seems that
>tcp.Port.connected is not being updated quickly enough to prevent the
>additional pendingTimedCalls
>
Port.stopListening can return a Deferred if shutdown is not immediately
completed. In this case, you need to have trial wait for this Deferred
to fire before letting the test finish. Also, Port.stopListening does
not cause Echo.connectionLost to be called. Shutting down a port only
prevents new connections from being made to it, it does not disconnect
any existing connections. Even if it did, it would be a bug if it gave
duplication connection lost notifications to any protocol. ;)
>My question therefore is how is it possible to cleanly shut down a server
>when a client connection is lost?
You might also consider disabling the port when the connection is /made/.
This reduces the size of the window available for a second connection to
be made, and as I mentioned above, has no affect on the already-established
connection.
Jean-Paul
More information about the Twisted-Python
mailing list