It's been a week break since I finished the very well received Plack Advent Calendar. And today i'm back on track on Plack development to get ready for the next week Perl Oasis in Orlando.
Streaming != Non-blocking
A few months ago we agreed on PSGI streaming interface for non-blocking applications and it's now implemented in most non-blocking backends like AnyEvent, Coro, Danga::Socket and POE. This is extremely useful to write non-blocking applications in an event driven callback style like Tatsumaki does.
Well, is feels a little weird that the extension is called "psgi.streaming" when we talk about non-blocking applications, doesn't it? At that time we kind of thought the name is confusing, but today it turns out limiting the streaming interface to "non-blocking" is what is confusing, and names are just correct.
Streaming interface is just an interface, and sure, CGI and mod_perl can also stream content if you call print to STDOUT or $r->print repeatedly, right? Streaming does not have anything to do with non-blocking event loop, and PSGI spec is ready for that: psgi.streaming can be true while psgi.nonblocking is false.
Of course, psgi.streaming is still really important for non-blocking apps to implement "delayed response" as well as "server push" using the event loop callback, but there's no reason streaming can not be done in blocking servers as well.
Do we really need it though?
Originally we didn't think about implementing the streaming interface in a blocking server backend, and a quick look of existing frameworks such as CGI::Application or Jifty don't seem to support that kind of non-buffering write. So our idea was that you should change the existing code to do IO-like object that gets a callback if you want to do streaming write. But well that is pull rather than push, so it needs to revert the control of the code, and the existing CGI apps or Catalyst apps that does non-buffering write from their controller code does not really work.
rafl, the Catalyst developer, showed up on our IRC channel #plack today, with the goal to kill Engine from Catalyst in his mind (w00t!), and asked if that kind of non-buffering write is possible without changing the existing users code, and we agreed that it's impossible unless we add psgi.streaming to blocking servers (such as Standalone, CGI and mod_perl) as well.
We already have a Writer middleware that does some kind of fallback, but that does a buffering write and that's not what we want here, so we started implementing non-buffering writes for the blocking servers and that is not particularly difficult.
There are some applications such as Tatsumaki or Plack::App::Proxy that use psgi.streaming and psgi.nonblocking extensions, and it's quite possible they confuse one from the other, and if psgi.streaming is available on most servers, their code can be much simplified. (If you use AnyEvent, just create a condvar and then ->recv on it if it's running in a blocking server)
I'm currently thinking of renaming Middleware::Writer to Middleware::BufferedStreaming so the users can use that middleware as a last resort when the server does not support streaming to run their application, though the ->write might be buffered, and probably promote the "MAY support psgi.streaming" to SHOULD.
Recent Comments