Suprising POE::Wheel::ReadWrite behaviour

Philip Gwyn <[email protected]> Fri, 17 Dec 2010 10:18:46 -0500
Newsgroups gmane.comp.lang.perl.poe
Message-ID <[email protected]>
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