On Aug 9, 2012, at 7:39 PM, Andrew Bennetts <[email protected]> wrote: Maxim Lacrima wrote: It's not this kind of buffering problem. I was actually able to reproduce it by replacing "Item.get()" with a deferLater. (In the future, please perform these types of replacements yourself before posting your examples; it's much easier to help out with complete, runnable programs.) The issue is that twisted.internet.stdio considers your protocol to only know about one kind of connection loss: i.e. that your entire transport has gone away. So, when the input is closed, the output file descriptor is immediately closed as well. Unfortunately - and I think this is a bug in Twisted - the input connection being lost causes the output connection to be immediately and somewhat aggressively closed. The difference between "echo" and typing interactively is that you send "test_item_id\n", but echo sends "test_item_id\n" *EOF*. Luckily you can work around this, by explicitly asking Twisted for notifications about half of the connection being closed. You do this by implementing IHalfCloseableProtocol. Although Twisted should be better about how it handles shutting down stdout, this nuance does reveal some logic that your code is missing: once your input is done, you don't have any concept of waiting for your output to be done before shutting everything down. So, if you add both the IHalfCloseableProtocol implements declaration to receive the relevant notifications, and some logic to keep track of when all the output has been written, you can get exactly the behavior that I assume you want. I've attached an example that does all of these things with a simple timer, since this is something that Twisted probably needs to document a bit better. |
from zope.interface import implements from twisted.internet import reactor, stdio, task from twisted.protocols import basic from twisted.internet.interfaces import IHalfCloseableProtocol
class EchoItemProtocol(basic.LineReceiver):
implements(IHalfCloseableProtocol)
delimiter = '\n'
def __init__(self):
self.outstanding = []
self.inputDone = False
def lineReceived(self, item_id):
# Item.get returns a deferred
d = task.deferLater(reactor, 1.0, lambda : item_id)
self.outstanding.append(d)
def writeResponse(item):
self.transport.write(str(item) + '\n')
d.addCallback(writeResponse)
def done(result):
self.outstanding.remove(d)
self.maybeDone()
return result
d.addBoth(done)
def readConnectionLost(self):
self.inputDone = True
self.maybeDone()
def maybeDone(self):
if self.inputDone and not self.outstanding:
self.transport.loseWriteConnection()
def writeConnectionLost(self):
reactor.stop()
def main():
stdio.StandardIO(EchoItemProtocol())
reactor.run()
if __name__ == '__main__':
main()
Cheers, -glyph |
_______________________________________________ Twisted-Python mailing list [email protected] http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
