Tatsuhiko Miyagawa's Blog

PSGI/Plack streaming is now complete

October 17, 2009

In the last couple of (or even more :) days Yuval and I have been endlessly discussing what the asynchronous response API would look like in PSGI applications. And that was also becoming one of the most frequently asked questions on my side, since many people from AnyEvent, POE and perlbal (Danga::Socket) land are curious how to port their non-blocking application to let them run on PSGI servers.

Thursday while having frodwith on board in the discussion (that was really helpful since he has a third person view as a POE developer) and we sorted out the nicely done middle ground, which is actually the revive of our original start_response callback we abandoned in favor of IO::Writer-like abstraction.

So, basically the idea is the same as the original Python WSGI’s start_response but this callback is NOT an optional parameter to the app because that stands in the way of everybody in the chain including middleware and that sucks. Instead, an app can optionally return a callback that accepts another callback to which you can return the response array ref (code, headers and body) if you want to delay your response.

my $app = sub {
  my $env = shift;
  return sub {
    my $respond = shift;
    # do some event stuff
    $event->callback(sub { $respod->([ $code, $headers, $body ]) });
  };
};

If you also want to delay the content body delivery as well (i.e. streaming) you can omit the body, in which case you’ll get the writer object that has write(), close() and poll_cb(). 

my $app = sub {
  my $env = shift;
  return sub {
    my $respond = shift;
    my $w = $respond->([ 200, [ 'Content-Type' => 'text/plain' ]]); # no $body here
    # do more event stuff
    $event->callback(sub { $w->write($body) });
    $event->done_callback(sub { $w->close });
  };
};

I plan to update the PSGI specification to address this optional response style in a few days. Yuval also has a nicely summarized blog post on this, and we already added this callback style to our AnyEvent, Danga::Socket, Coro and POE backend as well as most middlewares, including automatic chunking middleware (supposedly used by servers, not apps) which I line-by-line cloned from Rack :)

Meanwhile Yuval is working on his data-pimping REST machine Hydrant and I’ve been working on Real-Time-optimized web framework Tatsumaki, and both will be built on top of PSGI/Plack from the ground up. This will definitely be how web frameworks in Perl would look like in 2010.

Friday night I was at my friend’s party and five people talked to me how awesome Plack is and it’s changing the world. (Disclosure: it was a party full of my Six Apart co-workers and alumni like Artur, Randy and Simon, so that’s not that surprising :))