AnyEvent recursive blocking wait with Plack

Mike Schilli anyevent at perlmeister.com
Wed Mar 7 01:59:45 CET 2012


I'm hitting the 'recursive blocking wait' limitation in AnyEvent and
wonder how to work around it.

In order to make my application portable across web servers, I'm using
Plack, here's my sample script:

     #!/usr/local/bin/perl -w
     use strict;
     use Plack::Handler::AnyEvent::HTTPD;

     my $port = 9090;
     my $server = Plack::Handler::AnyEvent::HTTPD->new(
         port => $port,
     );

     $server->register_service( appref() );
       # main loop
     my $cv = AnyEvent->condvar();
     $cv->recv();

     sub appref {
         return sub {
             my( $env ) = @_;

             return ['200', [ content => 'text/plain' ], [ "bonk\n" ]];
         };
     }

This works well, but Plack requires that the 'app handler' *returns*
a data structure, whereas AnyEvent typically provides *callbacks*. This
leads to problems when the web application does something internally
that's using callbacks, because then all of a sudden, you can't simply
"return" data from the main function, because you're in a callback when
the data is ready.

For example, let's assume that within the "app handler" we want to 
use AnyEvent to perform a server-server request and return the result
to the requestor:

     sub appref {
         return sub {
             my( $env ) = @_;

             my $cv = AnyEvent->condvar();

             http_get "http://google.com", sub {
                 my( $body, $hdr ) = @_;

                 ### ??? Can't *return* data here
             };

             return ['200', [ content => 'text/html' ], [ "*need data*" ]];
         };
     }

We can't return data from within the callback, so the first idea is to
use a blocking condvar:

     #!/usr/local/bin/perl -w
     use strict;
     use Plack::Handler::AnyEvent::HTTPD;
     use AnyEvent::HTTP;

     my $port = 9090;
     my $server = Plack::Handler::AnyEvent::HTTPD->new(
         port => $port,
     );

     $server->register_service( appref() );

     my $main = AnyEvent->condvar();

       # main loop
     $main->recv();

     sub appref {
         return sub {
             my( $env ) = @_;

             my $cv = AnyEvent->condvar();

             http_get "http://google.com", sub {
                 my( $body, $hdr ) = @_;

                 $cv->send( $body );
             };

             return ['200', [ content => 'text/html' ], [ $cv->recv() ]];
         };
     }

But this of course runs into the limitation that you can't use blocking
condvars from within AnyEvent callbacks:

     AnyEvent::CondVar: recursive blocking wait detected at script line 37

Any ideas how to work around it? The problem seems to be that Plack requires 
a return value and can't work with a callback. Or does it?

Any help appreciated.

-- 
-- Mike

anyevent at perlmeister.com



More information about the anyevent mailing list