[Twisted-Python] Error (and response) handling in protocols
Jason Heeris
jason.heeris at gmail.com
Sun Feb 20 23:26:45 MST 2011
I'm still a little confused about exactly how to deal with errors and
responses using protocols and factories. I think a lot of my
misunderstanding stems from the fact that I'm using serial (and
inter-process) communications, both of which Twisted treats rather
differently from TCP based connections — and all of the documentation
is TCP-centric.
Anyway, say I have a serial device that I send a single-line command
to, and expect a certain format of response. There are about a hundred
possible commands, but they all follow the same pattern, so I have a
CommandProtocol (some details omitted):
class CommandProtocol(LineOnlyReceiver, TimeoutMixin):
# For LineOnlyReceiver
MAX_LENGTH = 20
def parseReply(self, line):
if line[0:4] != self.command:
raise CommandReplyError(self.command, self.line)
# Parse rest of response
return reply
def lineReceived(self, line):
self.setTimeout(None)
try:
reply = self.parseReply(line)
except:
# ...?
else:
self.factory.commandCompleted(reply)
# ...maybe?
finally:
self.loseConnection()
def connectionMade(self):
self.sendLine(self.construct_message())
self.setTimeout(self.DEFAULT_TIMEOUT)
So I can then write a factory with a buildProtocol method that takes
an object with the command string, sets the appropriate attributes on
the protocol, and returns that for use with the SerialPort transport.
Peticolas' tutorial[1] shows the protocol calling a factory method
when the correct data is received. I understand that part fine. But as
far as I can tell, all the error handling relies on the
ClientFactory's clientConnectionFailed method — and I have no idea
when or how this is triggered. I *am* under the impression that it
won't ever be triggered on a SerialTransport, though, which means it
won't work for me.
[1] https://github.com/jdavisp3/twisted-intro/blob/master/twisted-client-8/get-poetry.py#L64
What should my protocol do if there's an error? I notice that
protocols like LineReceiver and NetstringReceiver just silently ignore
such problems and let whatever handles connection failures sort it
out; but again, this won't work for a serial transport. Even
explicitly calling "loseConnection" won't trigger a subsequent
"connectionLost" call.
So how should I handle reply parsing errors, timeouts,
LineReceiver-internal errors (eg. a too-long line) and whatever else
might happen?
One approach I considered was for my factory to pass my protocol a
deferred. The factory would chain another deferred to this one which
it could return to the caller. The protocol could then callback or
errback *it's* deferred with a result or error. I know how to
implement this, but I see that none of the protocols in Twisted (or
any of the examples, or the tutorials) do anything like this — it's
all just assembly and disassembly of the data and a call to a factory
method. This makes me think that I'm doing it wrong. There's also the
fact that protocol errors will be handled inconsistently: errors in
*my* parsing methods will show up to callers of the factory methods,
but errors in Twisted's parsing will pass silently.
Another thing I could do is to have something like:
def lineReceived(self, line):
try:
reply = self.parseReply(line)
except:
self.factory.commandFailed(failure.Failure())
# ...other stuff from above
But again, this is inconsistent, and I've not seen anything else in
Twisted doing it this way.
So how I do I deal with protocol errors in a connectionless protocol?
Cheers,
Jason
More information about the Twisted-Python
mailing list