[Twisted-Python] Error (and response) handling in protocols

Jason Rennie jrennie at gmail.com
Mon Feb 21 09:45:43 EST 2011


(...catching up on this thread...)

On Mon, Feb 21, 2011 at 6:21 AM, Jason Heeris <jason.heeris at gmail.com>wrote:

> There's a connectionMade event when you do SerialPort(protocol, ...).
> There's no connectionLost event, even if you do that over and over
> again.
>

As Jean-Paul noted, that's a genuine bug with Twisted.  However, since
Twisted is pure python, you can likely override the SerialPort class and
make user-land changes to fix the issue.  Maybe you'd even be able to help
review or fix the bug? :)  See the following link for guidelines:

http://twistedmatrix.com/trac/wiki/TwistedDevelopment

Should I? I don't know. My problem is, as a newbie, I *just don't
> know* what the usual way to approach a problem like this is. Or if
> there is one.
>

IIUC, SerialPort doesn't work with the twisted factory infrastructure.
 Factories are used to persist data across different connections.  With
SerialPort, there's just one connection.  Any data you want to store (e.g. a
Deferred) should go in your protocol.

So, please help me think this through... let's say I have this
> long-lasting protocol. It needs to keep a DeferredLock, so it doesn't
> try to send one message before it's received the reply for another —
> right? It should have a method for sending a command that returns a
> Deferred, that will eventually fire with the response (parsed and
> converted as necessary, that bit's easy). The bit I have trouble with
> is that the *origin* of the Deferred callback or errback is the
> "lineReceived" method — somehow this method needs to know which
> Deferred to callback with the response. But how?
>

Sounds like you just need a queue of pending commands and a state object for
the currently executing command.  When runCommand() is called, add the
command to the pending queue.  If no command is running, pop the first
command in the queue and send it.  When you get a response, the state object
tells you what Deferred to fire.  Again, if there's a pending command, send
it.  Sketch:

def _runNext(self):
    if len(self.queue) > 0 and self.state == 'IDLE':
        self.state = 'PROCESSING'
        self.currentCmd, self.currentDeferred = self.queue.pop()
        self.sendLine(self.constructMessage(self.currentCmd))
def runCommand(self, command, callback):
    ret = Deferred()
    self.queue.append((command, ret))
    self._runNext(self)
    return ret
def lineReceived(self, line):
    self.state = 'IDLE'
    try:
        result = self.parseResponse(self.currentCmd, line)
        self.currentDeferred.callback(result)
    except Exception, err:
        self.currentDeferred.errback(err)
    self._runNext(self)


> PS. Twisted has great documentation for its individual components, but
> as soon as you get into anything that doesn't centre around
> "reactor.connectTCP", it seems like you're in the dark. All of the
> examples and tutorials seem to have near-trivial, completely
> synchronous protocols, requiring no back-and-forth or error handling.
> Ultimately I'd like to take all of this advice, have an epiphany,
> finish my project, bundle my new-found wisdom up into a neat little
> package of things I think would make serial comms a happier experience
> for all, and publish it somewhere. And maybe write about how to use
> Twisted for non-internetty things. But I do need to actually
> accomplish something first.


In case you haven't yet, see:

 http://twistedmatrix.com/pipermail/twisted-python/2011-January/023362.html

and follow-up threads.

Cheers,

Jason

-- 
Jason Rennie
Research Scientist, ITA Software
617-714-2645
http://www.itasoftware.com/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://twistedmatrix.com/pipermail/twisted-python/attachments/20110221/65e00e8c/attachment.htm 


More information about the Twisted-Python mailing list