2

I'm using twistd. Here is the sole service in the application:

class GameClientService(internet.TCPClient):
    def __init__(self, serverHost, serverPort):
        self.wxApp = wx.App(False)
        reactor.registerWxApp(self.wxApp)
        self.lobbyFrame = gui.LobbyFrame()

        internet.TCPClient.__init__(self, serverHost, serverPort, LobbyProtocolFactory(self.lobbyFrame))

    def stopService(self):
        internet.TCPClient.stopService(self)
        print "Stop service!"
        destroyedD = defer.Deferred()
        self.lobbyFrame.CloseWithCallback(destroyedD.callback, True)
        print "close called!"
        def fired(result):
            print "'Destroyed' deferred has fired with %s" % (result,)
        destroyedD.addCallback(fired)
        return destroyedD

CloseWithCallback is defind on the wx.Frame as follows:

def CloseWithCallback(self, callback, *callbackArgs):
    def destroyed(event):
        event.Skip()
        callback(*callbackArgs)
    self.Bind(wx.EVT_WINDOW_DESTROY, destroyed)
    self.Close()

In the LobbyProtocol's factory, I stop the reactor if a connection fails:

def clientConnectionFailed(self, connector, reason):
    print "Client connection failed: %s" % reason.getErrorMessage()
    reactor.stop()

I run the client without a listening server, so the connection fails, yet some of the time (maybe more than half, but not always):

2012-11-12 18:43:29-0500 [-] Started connecting <twisted.internet.tcp.Connector instance at 0x030E3800>
2012-11-12 18:43:30-0500 [Uninitialized] Client connection failed: Connection was refused by other side: 10061: No connection could be made because the target machine actively refused it..
2012-11-12 18:43:30-0500 [Uninitialized] Stopping factory <network.LobbyProtocol.LobbyProtocolFactory instance at 0x030E3698>
2012-11-12 18:43:30-0500 [-] Stop service!
2012-11-12 18:43:30-0500 [-] 'Destroyed' deferred has fired with True
2012-11-12 18:43:30-0500 [-] Traceback (most recent call last):
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 14669, in <lambda>
2012-11-12 18:43:30-0500 [-]     lambda event: event.callable(*event.args, **event.kw) )
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\site-packages\twisted\internet\_threadedselect.py", line 232, in _interleave
2012-11-12 18:43:30-0500 [-]     msg, args = self.toMainThread.get_nowait()
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\Queue.py", line 190, in get_nowait
2012-11-12 18:43:30-0500 [-]     return self.get(False)
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\Queue.py", line 165, in get
2012-11-12 18:43:30-0500 [-]     raise Empty
2012-11-12 18:43:30-0500 [-] Queue.Empty
2012-11-12 18:43:30-0500 [-] Server Shut Down.
2012-11-12 18:43:30-0500 [-] Server Shut Down.

This makes me uncomfortable. How can I make sure that traceback never runs? What have I done wrong?

Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 2
    It sounds like you're using wxreactor (though you didn't explicitly say so). wxreactor is effectively unmaintained due to lack of interest by members of the Twisted community. If you're interested in it, then you may benefit from providing some maintenance effort for it. eg, if you find undesirable behaviors which appear to be bugs (as this appears to be, based on the code you pasted) then you should file a bug report and attach a patch to fix the issue (you should at least do the former, so people will know there is a bug; the latter may also be necessary if you actually want it fixed). – Jean-Paul Calderone Nov 13 '12 at 01:26
  • 2
    @Jean-PaulCalderone: ah thanks for the tip! the idea of contributing useful things is appealing. i'll do so if i find i have the time – Claudiu Nov 13 '12 at 18:39

1 Answers1

2

I have performed the appropriate ablutions and thus my code is now purified:

class CleanExitApp(wx.App):
    def __init__(self, *args, **kwargs):
        wx.App.__init__(self, *args, **kwargs)

        self.exitDeferreds = []

    def AddExitDeferred(self, exitDeferred):
        self.exitDeferreds.append(exitDeferred)

    def OnExit(self):
        print "OnExit"
        for exitDeferred in self.exitDeferreds:
            exitDeferred.callback(True)

class GameClientService(internet.TCPClient):
    def __init__(self, serverHost, serverPort):
        self.wxApp = CleanExitApp(False)
        reactor.registerWxApp(self.wxApp)
        self.lobbyFrame = gui.LobbyFrame() 

        internet.TCPClient.__init__(self, serverHost, serverPort, LobbyProtocolFactory(self.lobbyFrame))

    def stopService(self):
        internet.TCPClient.stopService(self)
        print "Stop service!"
        exitD = defer.Deferred()
        self.wxApp.AddExitDeferred(exitD)
        self.lobbyFrame.Close()
        print "close called!"
        def fired(result):
            print "'Destroyed' deferred has fired with %s" % (result,)
        exitD.addCallback(fired)
        return exitD

Which graces us with the output:

2012-11-12 18:56:15-0500 [-] Started connecting <twisted.internet.tcp.Connector instance at 0x032AB8C8>
2012-11-12 18:56:16-0500 [Uninitialized] Client connection failed: Connection was refused by other side: 10061: No connection could be made because the target machine actively refused it..
2012-11-12 18:56:16-0500 [Uninitialized] Stopping factory <network.LobbyProtocol.LobbyProtocolFactory instance at 0x032AB7B0>
2012-11-12 18:56:16-0500 [-] Stop service!
2012-11-12 18:56:16-0500 [-] close called!
2012-11-12 18:56:16-0500 [-] OnExit
2012-11-12 18:56:16-0500 [-] 'Destroyed' deferred has fired with True
2012-11-12 18:56:16-0500 [-] Server Shut Down.
2012-11-12 18:56:16-0500 [-] Server Shut Down.

Praise the lord!

One only wonders if the lord had a different message in mind... a more built-in one that would not require such tortured codes?

Claudiu
  • 224,032
  • 165
  • 485
  • 680