[Python-ideas] PEP 3156 feedback

Antoine Pitrou solipsis at pitrou.net
Tue Dec 18 12:27:30 CET 2012


Le Tue, 18 Dec 2012 11:54:40 +0100,
"Amaury Forgeot d'Arc"
<amauryfa at gmail.com> a écrit :
> 2012/12/18 Antoine Pitrou
> <solipsis at pitrou.net>
> 
> > My own opinion about Twisted's API is that the Factory class is
> > often useless, and adds a cognitive burden. If you need a place to
> > track all protocols of a given kind (e.g. all connections), you can
> > do it yourself. Also, the Factory implies that you don't control
> > how exactly your protocol gets instantiated (unless you override
> > some method on the Factory I'm missing the name of: it is
> > cumbersome).
> >
> > So, when creating a client, I would pass it a protocol instance.
> >
> 
> Factories are useful to implement clients that reconnect
> automatically: the framework needs to spawn a new protocol object.
> The connect method could take a protocol class,
> but how would you implement the reconnect strategy?

I view it differently: the *same* protocol *instance* should be re-used
for the new connection. That's because the protocol can keep data that
lasts longer than a single connection (many protocols have session ids
or other state that can persist accross connections: this is typical
of RPC APIs affecting the state of an always-running equipment).

> We should be clear on what a protocol is. In my mind, a protocol
> manages the events on a given transport; it will also probably buffer
> data. For example, data for the HTTP protocol always starts with
> "GET ... HTTP/1.0\r\n".
> If a protocol can change transports in the middle, it can be
> difficult to track
> which socket you write to or receive from, and manage your buffers
> correctly.
> 
> An alternative could be a "reset()" method, but then we are not far
> from a factory class.

Well, the problem when switching transports is that you want to:
- wait for all outgoing data to be flushed
- migrate all pending incoming data to the new transport

IMO, this begs for a solution on the transport side, not on the client
side (some kind of migrate() API on the transport?). In other words,
you switch transports, but you keep the same protocol instance: when
your FTP protocol switches from plain TCP to TLS, it remembers the
current directory, etc.

> Also, this example from Twisted documentation:
>     attempt = myEndpoint.connect(myFactory)
>     reactor.callback(30, attempt.cancel)
> Even if these lines appear in my code, it's easier to have all errors
> caught in one place.

Ah, I think there's a misunderstanding.  Protocol.connection_lost()
should be called when an *established* connection is lost.

Indeed, there should be a separate Protocol.connection_failed() method
for when the connect() calls never succeeds (either times out or returns
with an error). And this is a reason why it is better for the transport
to be registered early on the protocol (or vice-versa) :-)

Regards

Antoine.





More information about the Python-ideas mailing list