Permalink
Browse files

updated FAQ for the streaming

  • Loading branch information...
miyagawa committed Oct 22, 2009
1 parent 667bda2 commit 41a378441eaf69e7eb8ebf23592523339254445d
Showing with 69 additions and 27 deletions.
  1. +69 −27 PSGI/FAQ.pod
View
@@ -432,14 +432,67 @@ optimized in even more environments.
=head3 What if I want to stream content or do a long-poll Comet?
-For the server push, your application can return a IO::Handle-like
-object as a content body that implements C<getline> to return pushed
-content. Some implementations are also allowed to do an optimized
-non-blocking read from special filehandle-like objects like
-L<IO::Writer>.
+The most straightforward way to implement server push is for your
+application to return a IO::Handle-like object as a content body that
+implements C<getline> to return pushed content. This is guaranteed to
+work everywhere, but it's more like L<pull> than L<push>, and it's
+hard to do non-blocking I/O unless you use Coro.
+
+If you want to do server push, where your application runs in an event
+loop and push content body to the client as it's ready, you should
+first check if the server supports the delayed response, by looking at
+C<psgi.streaming> env hash, and then return a callback to delay the
+response.
+
+ # long-poll comet like a chat application
+ my $app = sub {
+ my $env = shift;
+ unless ($env->{'psgi.streaming'}) {
+ die "This application needs psgi.streaming support";
+ }
+ return sub {
+ my $respond = shift;
+ wait_for_new_message(sub {
+ my $message = shift;
+ my $body = [ $message->to_json ];
+ $respond->([200, ['Content-Type', 'application/json'], $body]);
+ });
+ };
+ };
+
+C<wait_for_new_message> can be blocking or non-blocking: it's up to
+you. Most of the case you want to run it non-blockingly and should use
+event loops like L<AnyEvent>. You're suggested to check
+C<psgi.nonblocking> value to see that it's possible.
+
+Also, to stream the content body (like streaming messages over the
+Flash socket or multipart XMLHTTPRequest):
+
+ my $app = sub {
+ my $env = shift;
+ unless ($env->{'psgi.streaming'}) {
+ die "This application needs psgi.streaming support";
+ }
+ return sub {
+ my $respond = shift;
+ my $writer = $respond->([200, ['Content-Type', 'text/plain']]);
+ wait_for_new_message(sub {
+ my $message = shift;
+ if ($message) {
+ $writer->poll_cb(sub {
+ $_[0]->write($message->to_json);
+ });
+ } else {
+ $writer->close;
+ }
+ });
+ };
+ };
-Fo the long poll comet you can also use co-routine based
-implementations like L<Plack::Server::Coro> and do your own threading.
+C<poll_cb> pushes the callback to the buffer to write your content
+whenever a client is ready to receive the content. You can just use
+C<write> instead of C<poll_cb> but that might cause a problem if you
+stream a massive streaming content against a slow HTTP client.
=head3 Which framework should I use to do streaming though?
@@ -453,34 +506,23 @@ on the response object:
}
But it obviously blocks in the application unless you run your
-application in multithread (or Coro)
-environments. L<Catalyst::Engine::PSGI> also supports setting an
-IO::Handle-like object that supports C<getline>, so using
-L<IO::Handle::Util>
+application in multithread (or Coro) environments.
+L<Catalyst::Engine::PSGI> also supports setting an IO::Handle-like
+object that supports C<getline>, so using L<IO::Handle::Util>
my $io = io_from_getline sub {
return $data; # or undef when done()
};
$c->res->body($io);
-And that works fine to do streaming, but it's blocking so you should
-be careful not to run on non-blocking (and non-multiprocess) server
+And that works fine to do streaming, but it's blocking (L<pull>)
+rather than server push, so you should be careful not to run this
+application on non-blocking (and non-multiprocess) server
environments.
-For the nonblocking single process server (like AnyEvent or Perlbal)
-the solution we're working on is a non-blocking IO handle that falls
-back to blocking, called L<IO::Writer>. Once we figure that out, then
-you can set the writer object to response body, like:
-
- my $io = writer {
- my $handle = shift;
- $handle->print($stuff);
- };
-
- $c->res->body($io);
-
-And it will do the right thing in blocking and non-blocking server
-environments transparently.
+We expect that more web frameworks will appear that is focused on, or
+existent frameworks will add support for, asynchronous and
+non-blocking streaming interface.
=head3 Why CGI-style environment variables instead of HTTP headers as a hash?

0 comments on commit 41a3784

Please sign in to comment.