[ python-Bugs-1370380 ] asynchat.async_chat.push() function doesnt say when failed

SourceForge.net noreply at sourceforge.net
Thu Dec 15 09:32:19 CET 2005


Bugs item #1370380, was opened at 2005-11-30 13:18
Message generated for change (Comment added) made by josiahcarlson
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1370380&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Python Library
Group: Python 2.4
Status: Open
Resolution: None
Priority: 5
Submitted By: Jan David Mol (jjdmol)
Assigned to: Nobody/Anonymous (nobody)
Summary: asynchat.async_chat.push() function doesnt say when failed

Initial Comment:
suppose you have a socket handled by your asynchat.async_chat class 
and want to send a message (call push()). push() calls initiate_send(), 
which can call handle_error() if an error occurs. however, once 
handle_error() returns, the control is passed back to push(), which has 
no return value thus cannot signal the success or failure to the code 
that did the push(). i.e. if we have code like

foo()
s.push(data)
bar()

the following is executed in case of an error:

foo()
s.push(data)
s.handle_error()
bar()

this created an obscure bug, as the bar() assumed the send() always 
succeeds, and also cannot check directly by the result of push() if it 
did. this creates the false illusion push() can never fail.

to avoid this, handle_error() can set a flag, which can be checked after 
the push(). however, this is an ugly hack of course.

PS: send() can easily fail. suppose we're reading from 2 sockets: A and 
B, and send messages to both when data is read from either one. if B 
gets disconnected and A has data ready, both will be in the set of 
readible sockets returned by select(). if A's data is handled before B's, 
and A sends a message to B, this will cause the send to fail as B is 
disconnected. your app wont know B failed, because this is processed 
after the data from A is processed.

----------------------------------------------------------------------

Comment By: Josiah Carlson (josiahcarlson)
Date: 2005-12-15 00:32

Message:
Logged In: YES 
user_id=341410

Here's a subclass that doesn't send on push...

class MyAsyncChat(asynchat.async_chat):
    def push (self, data):
        self.producer_fifo.push (simple_producer (data))

That's it.

And according to my reading of asynchat and asyncore, while
actually trying to send data during a push() may trigger the
handle_error() method to be called, by default, the
handle_error() method logs the error and closes the socket.
 Errors don't seem to propagate out of push().

----------------------------------------------------------------------

Comment By: Jan David Mol (jjdmol)
Date: 2005-12-15 00:18

Message:
Logged In: YES 
user_id=516066

Push() sending data may indeed be the source of the problems here. There 
should be no problems with delaying the write until the next select() will tell 
the socket is writable.

My current work around is indeed subclassing as you describe. However, it 
seemed that such a thing would be exactly that: a work around in order to 
obtain expected behaviour.

So a suggestion: push() should either not try to send, or should communicate 
back to its caller when an error occurs. Having an error handler set an error 
code to check is so 80s, but that could be just me :)

Maybe push() not sending is the nicer of the two solutions. There is little 
reason why it can't wait till the next select() call returns the socket as 
writable.

If nothing is changed, the documentation should contain that handle_error() 
can be triggered even though one is only adding stuff to a FIFO buffer (or so 
the description of push() makes it seem). Reading the docs doesn't prepare 
you for the control flow as I first described. In all the other handle_error 
invocations, handle_error() isn't called from within your code unless you raise 
exceptions in your part of the handle_read/write/accept/connect code. Even 
in asyncore, send() gives you an exception instead, creating an inconsistency 
with asynchat's push(), as both can fail.

----------------------------------------------------------------------

Comment By: Josiah Carlson (josiahcarlson)
Date: 2005-12-13 22:16

Message:
Logged In: YES 
user_id=341410

Not a bug.  The control for deciding how to handle an error
in a connection is defined by the instance method
handle_error().  If you would like custom error handling in
your instances, perhaps you should subclass async_chat...

import asynchat

class MyAsyncChat(asynchat.async_chat):
    error = 0
    def handle_error(self):
        self.error = 1
        asynchat.async_chat.handle_error(self)
    def push(self, data):
        self.error = 0
        asynchat.async_chat.push(self, data)
        return self.error

Also, the fact that async_chat.push() ends up trying to send
data, is, in my opinion, a misfeature in implementation. 
Under certain circumstances it can increase data throughput,
but it removes the standard asyncore.loop/poll() from the
control flow.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1370380&group_id=5470


More information about the Python-bugs-list mailing list