[Twisted-Python] Qtreactor problem on twisted 2.1

Hello, Our application uses twisted as the core network framework. It basically consists of a server and multiple clients. All communication is carried on a twisted.spread.pb channel. We have been using twisted 1.3 since the beginning, we decided to switch to twisted 2.1, the switch was easy but an interesting problem showed up. Our client is based on PyQt, so uses qtreactor. If something goes wrong on the server side, the error is transferred to the client (automagically, thanks to twisted & deferreds), and handled there (with an errback). We warn our users about the failure with a dialog. The interesting part is, with twisted 2.1, at the dialog's exec_loop() call, occasionally the connection between the server and client goes away with the following exception: ------------------------------------------- 2005/12/30 15:51 GTB Standard Time [-] Error in <<class 'twisted.internet.tcp.TLSConnection'> to (u'localhost', 4243) at 1312e50>.doRead() 2005/12/30 15:51 GTB Standard Time [-] Traceback (most recent call last): File "C:\Python24\Lib\site-packages\twisted\internet\defer.py", line 182, in addCallbacks self._runCallbacks() File "C:\Python24\Lib\site-packages\twisted\internet\defer.py", line 307, in _runCallbacks self.result = callback(self.result, *args, **kw) File ".\lq\lqtrxutils.py", line 126, in eb_localFailed File ".\lq\lqdialog.py", line 201, in showDialog --- <exception caught here> --- File "C:\Python24\Lib\site-packages\twisted\internet\qtreactor.py", line 62, in read why = w.doRead() File "C:\Python24\Lib\site-packages\twisted\internet\tcp.py", line 111, in doRead return Connection.doRead(self) File "C:\Python24\Lib\site-packages\twisted\internet\tcp.py", line 347, in doRead return self.protocol.dataReceived(data) File "C:\Python24\Lib\site-packages\twisted\spread\banana.py", line 173, in dataReceived gotItem(self.incomingVocabulary[num]) File "C:\Python24\Lib\site-packages\twisted\spread\banana.py", line 114, in gotItem self.callExpressionReceived(item) File "C:\Python24\Lib\site-packages\twisted\spread\banana.py", line 81, in callExpressionReceived self.expressionReceived(obj) File "C:\Python24\Lib\site-packages\twisted\spread\pb.py", line 567, in expressionReceived raise ProtocolError("Non-list expression received.") twisted.spread.pb.ProtocolError: Non-list expression received. 2005/12/30 15:51 GTB Standard Time [-] <twisted.internet.ssl.Connector instance at 0x0134BE90> will retry in 2 seconds 2005/12/30 15:51 GTB Standard Time [-] Stopping factory <lqclientfactory.lqClientFactory instance at 0x0134BDF0> ------------------------------------------- Line 201 at lqdialog.py reads as result = self.exec_loop() We are using a reconnecting client factory, the application reconnects in a matter of seconds but this behaviour is annoying. As I wrote above, the we had no problem when using 1.3. Any ideas? Regards, and happy new year! Umit Oztosun P.S.: Tested on both Windows XP and Ubuntu Linux (5.10 and 5.04). Disconnection occurs regardless of using or not using SSL.

On Dec 30, 2005, at 10:26 AM, Umit Oztosun wrote:
Hello,
Our application uses twisted as the core network framework. It basically consists of a server and multiple clients. All communication is carried on a twisted.spread.pb channel. We have been using twisted 1.3 since the beginning, we decided to switch to twisted 2.1, the switch was easy but an interesting problem showed up.
Our client is based on PyQt, so uses qtreactor. If something goes wrong on the server side, the error is transferred to the client (automagically, thanks to twisted & deferreds), and handled there (with an errback). We warn our users about the failure with a dialog. The interesting part is, with twisted 2.1, at the dialog's exec_loop() call, occasionally the connection between the server and client goes away with the following exception:
For some reason, the stack trace looks truncated, since it starts with defer.py:addCallbacks. But my guess is that read is getting called re-entrantly. By calling exec_loop within a callback, you're causing the reactor to loop within another reactor loop, and the reactor isn't designed to ensure it's safe to do that. Is it possible to change the code to show a dialog box without running a sub-loop? James

Hi, On 12/30/05, James Y Knight <foom@fuhm.net> wrote:
For some reason, the stack trace looks truncated, since it starts with defer.py:addCallbacks. But my guess is that read is getting called re-entrantly. By calling exec_loop within a callback, you're causing the reactor to loop within another reactor loop, and the reactor isn't designed to ensure it's safe to do that. Is it possible to change the code to show a dialog box without running a sub-loop?
Well, our dialog is a custom widget derived from QDialog. Displaying the dialog without exec_loop is not a problem, but in order to receive and process GUI events, one should somehow call qApp.processEvents() or a similar call. Otherwise GUI basically locks up. I constructed a dummy loop periodically calling qApp.processEvents() in order to simulate the exec_loop behaviour. However, the problem still persists. After a few seconds after the dialog is displayed, the "Non-list expression received" exception is fired. I even tried "qApp.eventLoop().processEvents(QEventLoop.ExcludeSocketNotifiers)" in order to only process user input events, but this again didn't work. This does not always happen, but happens quite occasionally. To emphasize again, problem does not exist when using twisted 1.3. I also tried to connect a twisted 2.1 server with a twisted 1.3 client, and it was still OK. Regards, Umit Oztosun
participants (2)
-
James Y Knight
-
Umit Oztosun