Re: Suprising POE::Wheel::ReadWrite behaviour

Markus Müller <[email protected]> Sat, 18 Dec 2010 14:12:46 +0100
Newsgroups gmane.comp.lang.perl.poe
Message-ID <[email protected]>
Hi Philip,

I am writing since many years POE projects. One of the
first things I figured out in productive environment is to
test the poe object with defined() and ref(). I had so often
programs  running over days or weeks and then just
stopping with a "Can't  call method on undefined value",
so I today do defined() and ref() test on any POE object call.
Especially on put!

This looks for example like this:

$heap->{server}->{$wheel_id}->{wheel}->put('xyz')
if (exists 
<http://perldoc.perl.org/functions/exists.html>($heap->{server}->{$wheel_id}->{wheel}) 
&&
defined 
<http://perldoc.perl.org/functions/defined.html>($heap->{server}->{$wheel_id}->{wheel}) 
&&
(ref 
<http://perldoc.perl.org/functions/ref.html>($heap->{server}->{$wheel_id}->{wheel}) 
eq "POE::Wheel::ReadWrite"));

Much regards,
Markus Mueller
> While writing http://search.cpan.org/dist/POEx-HTTP-Server/ I've discovered a
> behaviour of POE::Wheel::ReadWrite that is suprising, to say the least.  I
> share it here because I suspect I'm not the only one this has bitten.
>
> I had the following 2 lines
>       $heap->{wheel}->flush();
>       my $h = $self->{wheel}->get_output_handle;
>
> The symptom was that the second of these two lines would sometimes throw a
> "Can't call method on undefined value" error.  Which caused me to bang my
> head on the desk for a while.
>
> But then it dawned on me:
>     - ->flush() pushes the data down to the OS layer;
>     - POE is then getting a select() in somehow (haven't tracked this down);
>     - the select shows the Wheel's write handle is ready;
>     - the Wheel's write handler is invoked;
>     - which invokes my "flushed" handler;
>     - the flushed handler was deleting the wheel;
>     - all the happens before ->flush returns;
>     - by the time it returns, $self->{wheel} has been deleted.
>
> The answer isn't don't use ->flush(), because ->put() can trigger a driver's
> ->flush(), or call it explicitly if you have autoflush on.
>
> The solution is that all code that uses of ReadWrite need better detection of
> "end of connection."
>
> Now, is this "gotcha" documented anywhere?  Should it be?  Should there be a
> module that turns ReadWrite's asynchronous behaviour into something easier to
> deal with?
>
> I suspect the answer to the last question is "yes, and you've just volunteered
> to write it, dude."
>
> -Philip
>
>
>