I'm the maintainer of a similar project for clojure called noir-async. Noir is built on ring, clojure's version of rack, and has no notion of streaming responses, but adding it in wasn't a problem at all (https://github.com/andrewvc/noir-async).
In other words, it's not a big deal. Most streaming code should really be a separate app anyway. Apps that deliver true streams probably need different infrastructure from say a rails app. You want a separate process running a reactor to handle concurrent IO.
"Most streaming code should really be a separate app anyway."
A great deal of the reason you are saying that is because it's too hard to do anything else today. That doesn't make it the right answer.
It is far easier to take a fundamentally-streaming stack and layer conventional request-response on top as a special case than it is to take a conventional request-response stack and layer a stream on top of that. It isn't even that much harder to do it right if you start with that from day 1, but I've had a devil of a time convincing anyone in the early phases of web framework development of that. ("Why don't you do it yourself?" I'm full up for spare time projects at the moment... and also, I'm really trying to resist adding yet another web framework to the world.)
Of course sometimes the right answer really is a separate app. But you should do that because it's the right answer, not because your stack forced you to do it that way.
"It is far easier to take a fundamentally-streaming stack and layer conventional request-response on top as a special case than it is to take a conventional request-response stack and layer a stream on top of that."
This is demonstrably true in that Rack/etc are themselves almost always built on top of conventional socket-based streaming APIs. Streaming APIs have been the norm, and yet people choose to put abstractions on top of them. Why? Mostly because it gives substantial improvements to application code, and turns the system into more of a set of contracts and less of a mushy touch-any-object-you-want system, which I think is fundamental to how streaming works, due to its imperative nature.
Using Rack or any of its equivalents, it would be fairly easy to allow a hole to be punched through the system to give a direct socket streaming API. Just toss the relevant objects into the request. It would violate the abstractions of Rack, any middleware, etc. But you can do it, and it would be easy. It's not unlike using Rack instead of the abstractions Rails puts on top of it – arguably it can be useful shortcut parts of the stack.
Why don't people do this? Mostly because no one cares to. It's not that useful or interesting or testable. It's noticeable enough that people complain about it, but not noticeable enough to be worth it to take the hit and use a more imperative API.
I would submit you also have the causality backward and are also talking about the results of the current factoring, not the cause. It is definitely not true that you have a choice between response/request and an abstractionless formless mass of a socket. I offer you XMPP as one readily-available counterexample. HTTP itself, if properly and fully implemented, is actually another. It worked itself into a streaming protocol, and many frameworks never noticed. This is part of the reason this cheeses me off so much, because even the putatively-HTTP frameworks can't actually speak the fullness of HTTP. Oh, and good luck supporting the full range of SPDY in your request-response framework.
The idea that streaming can't have abstractions put on it is beyond bizarre.
It is far easier to take a fundamentally-streaming stack and layer conventional request-response on top as a special case than it is to take a conventional request-response stack and layer a stream on top of that.
You're asking the wrong question. The right question is how much of a problem is it for your conventional request-response app to be built on top of something that really wants the streaming aspects exposed. And the answer is quite a bit.
For example, there are significant performance benefits to putting caching proxies in front of applications. But whether that is a reverse proxy sitting at your hosting facility or a distributed proxy that you're getting from Akamai, they introduce a strong assumption that you're not going to stream content through them.
So stuff you're going to likely want to do anyways at some point pushes you to want to separate request-response from streaming. And if are going to make that choice anyways, it makes little sense to add any complexity to your life at all to try and keep those together.
You don't want to do it because it's hard. If it wasn't hard, you'd do it more. It shouldn't be hard. Our collective reaction to websockets shouldn't be flipping out at how cool they are, it should be "it's about time you gave me back the things you took away".
Of course you want a strong page framework built on top, but the point really is it's easier to start with the streams underneath and build something that limits the streams to the request-response cycle than to go the other way, not that request-response isn't an important simplification that is frequently useful or that it shouldn't be very strong itself.
But you shouldn't go and write it into your WSGI standard or hard-wire your shiny new web server to insist on what are morally CGI pages, and break down crying if somebody wants to stream a little bit.
> It is far easier to take a fundementally-streaming stack and layer conventional request-response on top as a special case than it is to take a conventional request-response stack and layer a stream on top of that.
You can certainly work around it but the trade-offs of working around are very platform specific. For example, Node.js or Erlang apps do not need another infrastructure because streaming is in their foundation, there is no need at all for another stack. On the other hand, rack-stream forces you to use thin (so you can choose in having a specific stack or deploying it all together with thin).
In any case, the main point of the blog post is the amount of effort required in wrapping existing Rack middleware so they play along with streaming but still in a non-optimal way. For example, see the connection management middleware in Active Record:
Even more, if your rack-stream middleware is after the connection management middleware, each stream loop will first need to pass through the proxy call. The longer your stack, more proxies it will likely have and more cost will be involved in each stream.
So yes, you can work around but requires a lot of extra work and is not as efficient.
I disagree, the add-on I wrote, noir-async (which is really just sugar for noir + aleph), fully supports mixed streaming and chunked.
However, the reason I wrote that non-streaming endpoints should be separate apps is that their performance profile tends to be radically different, and you probably want those concerns separated.
Right, websockets servers tend to need NIO otherwise you just wind up with too many threads to manage. However, streaming has uses outside of websockets; for instance, returning a response that's too large to want to hold in memory.
Or simply flushing out the <head> of a html document before the body is generated so the browser can start pre-fetching resources. That's the main use case that motivated Rails to implement streaming.
You can do everything with Mongrel2 because of its beautiful asynchronous architecture. The really nice side effect is that you can share easily information between all the elements of your application which is not necessarily streaming of music/video. In my case, this allows me to "stream" results of scientific computations.
One approach we've experimented with in JSGI is a similar API to Rack but with the addition of promises to add an asynchronous mode of operation. It's theoretically elegant, but a bit awkward in practice.
I'm the maintainer of a similar project for clojure called noir-async. Noir is built on ring, clojure's version of rack, and has no notion of streaming responses, but adding it in wasn't a problem at all (https://github.com/andrewvc/noir-async).
In other words, it's not a big deal. Most streaming code should really be a separate app anyway. Apps that deliver true streams probably need different infrastructure from say a rails app. You want a separate process running a reactor to handle concurrent IO.