librelist archives

« back to archive

"middleware" and loopback

"middleware" and loopback

From:
Mathijs Kwik
Date:
2011-05-09 @ 07:05
Hi all,

What would be the best way to implement something like a generic
caching layer that can be placed between mongrel2 and a backend?
I can think of 2 possible ways for now and I propose a third one.

First possibility would be to just plug the caching app into mongrel2
and have its backends connect to that (probably using 0mq for that).
I think this complicates the infrastructure, because the caching app
needs to replicate a lot of the functionality in mongrel2 to interact
with its backends.

Secondly:
Plug both the caching app and the backend into mongrel2, caching app
on "normal" url, backend on some "internal" url.
The caching app can then just use http to do new requests on mongrel2
on this "internal" url.

A nicer solution (which I think isn't there at the moment) that I
think would be nicer:
Allow a backend to issue requests at mongrel2 using a 0mq socket.
This way, requests don't have to be parsed twice, probably increasing
performance.

A lot of special "middleware" apps can be created that use this functionality.

Are there plans to support anything like this?

Thanks,
Mathijs

Re: [mongrel2] "middleware" and loopback

From:
Zed A. Shaw
Date:
2011-05-10 @ 17:26
On Mon, May 09, 2011 at 09:05:14AM +0200, Mathijs Kwik wrote:
> Hi all,
> A nicer solution (which I think isn't there at the moment) that I
> think would be nicer:
> Allow a backend to issue requests at mongrel2 using a 0mq socket.
> This way, requests don't have to be parsed twice, probably increasing
> performance.

So, something like special responses that say things like:

* just send data X again.
* cache data X for 20 minutes
* invalidate data X right now

And so on?

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] "middleware" and loopback

From:
Mathijs Kwik
Date:
2011-05-10 @ 19:44
Hi Zed,

Well I wasn't saying mongrel2 should do the caching or something like that.
I was suggesting that there can be a wide range of apps that are not
"endpoints" that generate the full response themselves, but rather
intercept requests (or responses) to change/enhance/check them some
more.
Think about additional/separate authentication, special
logging/tracing, optimizing for certain devices (compressing images),
single-signon between apps, and caching as well.
These applications need to mangle the incoming request, forward that
to the "real" app (or some other layer in the middleware stack),
receive the response back, mangle that some more, and send the final
response back.
If they need to communicate/signal each other, this usually
piggy-backs on some special headers.
In other words, apps need to be able to nest and forward (changed)
requests and responses to each other.
Like a before- and after filter.
I'm sure you're familiar with the middleware concept that ruby's rack
stack uses, this is exactly what I'm looking for.

Having to connect those "middleware" apps yourself largely defeats the
purpose of mongrel2, even while 0mq is a big help.
So it would be great if mongrel2's config could be used to put these
stacks together.

One way to emulate this now is to have the "real" app listen on
"myapp.internal" on mongrel2 and have a middleware app listen on
myapp.com. After doing its thing, the middleware app can just use an
http client to send the modified request to myapp.internal (on
mongrel2), wait for the response(preferably without blocking), modify
that, and finally hand it back to mongrel2 to be replied to the
client.
This however, is not very efficient. For one, the modified request has
to be re-parsed when it arrives for myapp.internal. Also, the
middleware app itself is responsible for an efficient event-loop (so
it can accept new requests while waiting for the response of the first
one). It would be great if mongrel2's internals can be exposed a
little more, so these middleware apps can just let mongrel2 handle
these dirty details.

So what I would like is a special response like:
"this is not the real response, but rather a new request for app X"
(headers/body netstrings, so no need to re-parse)

And a special kind of request like:
"this is the response from app X"

Then you should be able to configure mongrel2 to "insert" apps between
the request/response streams of other apps.
I think there are 3 cases to consider:

- middleware apps that just modify a request
They receive the incoming request, decide to answer themselves (for
example a "hit" on a cache middleware), or to forward the (modified)
request to app X.
For that they use the special response.
The listener id is forwarded to app X as well, so when app X responds,
it responds directly to the original client

- middleware apps that just modify a response
Mongrel2 receives a request for app X.
Mongrel2 modifies the listener id to something special.
When app X responds, mongrel2 recognizes the special listener id and
knows to forward the response to the middleware using the special
request type.
The middleware app does its thing, and responds to the original listener id.

- middleware apps that do both the above


I hope this makes my wishes a bit clearer.
As stated, the behavior of ruby's rack stack is just the thing I need.
However, it would be very cool if mongrel2 could give me this same
behavior, but with the usual advantages (especially language agnostic)
so I can write middlewares in languages that I see fit.

Any chance something like that will make it into mongrel2?

Thanks,
Mathijs



On Tue, May 10, 2011 at 7:26 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
> On Mon, May 09, 2011 at 09:05:14AM +0200, Mathijs Kwik wrote:
>> Hi all,
>> A nicer solution (which I think isn't there at the moment) that I
>> think would be nicer:
>> Allow a backend to issue requests at mongrel2 using a 0mq socket.
>> This way, requests don't have to be parsed twice, probably increasing
>> performance.
>
> So, something like special responses that say things like:
>
> * just send data X again.
> * cache data X for 20 minutes
> * invalidate data X right now
>
> And so on?
>
> --
> Zed A. Shaw
> http://zedshaw.com/
>

Re: [mongrel2] "middleware" and loopback

From:
Jason Miller
Date:
2011-05-10 @ 22:17
I guess I must be confused.  This seems more inefficient then just
modifying the request and sending it on to the handler.  That is just
have the middleware be *actually* in the middle.  If you don't need to
rewrite responses, then you only really have to be in the middle for the
push/pull, which is even better.

I don't see how having to connect the middleware apps yourself defeats
the purpose of mongrel2 at all.  If it's something that is actually
valuable, then there will eventually be library(ies) that make it simple

-Jason

On 21:44 Tue 10 May     , Mathijs Kwik wrote:
> Hi Zed,
> 
> Well I wasn't saying mongrel2 should do the caching or something like that.
> I was suggesting that there can be a wide range of apps that are not
> "endpoints" that generate the full response themselves, but rather
> intercept requests (or responses) to change/enhance/check them some
> more.
> Think about additional/separate authentication, special
> logging/tracing, optimizing for certain devices (compressing images),
> single-signon between apps, and caching as well.
> These applications need to mangle the incoming request, forward that
> to the "real" app (or some other layer in the middleware stack),
> receive the response back, mangle that some more, and send the final
> response back.
> If they need to communicate/signal each other, this usually
> piggy-backs on some special headers.
> In other words, apps need to be able to nest and forward (changed)
> requests and responses to each other.
> Like a before- and after filter.
> I'm sure you're familiar with the middleware concept that ruby's rack
> stack uses, this is exactly what I'm looking for.
> 
> Having to connect those "middleware" apps yourself largely defeats the
> purpose of mongrel2, even while 0mq is a big help.
> So it would be great if mongrel2's config could be used to put these
> stacks together.
> 
> One way to emulate this now is to have the "real" app listen on
> "myapp.internal" on mongrel2 and have a middleware app listen on
> myapp.com. After doing its thing, the middleware app can just use an
> http client to send the modified request to myapp.internal (on
> mongrel2), wait for the response(preferably without blocking), modify
> that, and finally hand it back to mongrel2 to be replied to the
> client.
> This however, is not very efficient. For one, the modified request has
> to be re-parsed when it arrives for myapp.internal. Also, the
> middleware app itself is responsible for an efficient event-loop (so
> it can accept new requests while waiting for the response of the first
> one). It would be great if mongrel2's internals can be exposed a
> little more, so these middleware apps can just let mongrel2 handle
> these dirty details.
> 
> So what I would like is a special response like:
> "this is not the real response, but rather a new request for app X"
> (headers/body netstrings, so no need to re-parse)
> 
> And a special kind of request like:
> "this is the response from app X"
> 
> Then you should be able to configure mongrel2 to "insert" apps between
> the request/response streams of other apps.
> I think there are 3 cases to consider:
> 
> - middleware apps that just modify a request
> They receive the incoming request, decide to answer themselves (for
> example a "hit" on a cache middleware), or to forward the (modified)
> request to app X.
> For that they use the special response.
> The listener id is forwarded to app X as well, so when app X responds,
> it responds directly to the original client
> 
> - middleware apps that just modify a response
> Mongrel2 receives a request for app X.
> Mongrel2 modifies the listener id to something special.
> When app X responds, mongrel2 recognizes the special listener id and
> knows to forward the response to the middleware using the special
> request type.
> The middleware app does its thing, and responds to the original listener id.
> 
> - middleware apps that do both the above
> 
> 
> I hope this makes my wishes a bit clearer.
> As stated, the behavior of ruby's rack stack is just the thing I need.
> However, it would be very cool if mongrel2 could give me this same
> behavior, but with the usual advantages (especially language agnostic)
> so I can write middlewares in languages that I see fit.
> 
> Any chance something like that will make it into mongrel2?
> 
> Thanks,
> Mathijs
> 
> 
> 
> On Tue, May 10, 2011 at 7:26 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
> > On Mon, May 09, 2011 at 09:05:14AM +0200, Mathijs Kwik wrote:
> >> Hi all,
> >> A nicer solution (which I think isn't there at the moment) that I
> >> think would be nicer:
> >> Allow a backend to issue requests at mongrel2 using a 0mq socket.
> >> This way, requests don't have to be parsed twice, probably increasing
> >> performance.
> >
> > So, something like special responses that say things like:
> >
> > * just send data X again.
> > * cache data X for 20 minutes
> > * invalidate data X right now
> >
> > And so on?
> >
> > --
> > Zed A. Shaw
> > http://zedshaw.com/
> >
> 

Re: [mongrel2] "middleware" and loopback

From:
Zed A. Shaw
Date:
2011-05-11 @ 15:00
On Tue, May 10, 2011 at 03:17:07PM -0700, Jason Miller wrote:
> I guess I must be confused.  This seems more inefficient then just
> modifying the request and sending it on to the handler.  That is just
> have the middleware be *actually* in the middle.  If you don't need to
> rewrite responses, then you only really have to be in the middle for the
> push/pull, which is even better.

Nobody said more "efficient", I said easier to do, and mostly because it
involves a lot less gear and configuration.

If it's efficiency you need then that's what the filters will be for.

> I don't see how having to connect the middleware apps yourself defeats
> the purpose of mongrel2 at all.  If it's something that is actually
> valuable, then there will eventually be library(ies) that make it simple

That's what I'm imagining too.  It'll be the same pattern I go for in
most of my software:  There's a core simple API for filters and then
people go crazy making their own things others can inject.  That's what
happened with the handler protocol, so no reason it won't happen with
the filters too.

The thing I'm sort of worried about is that people will take the
filters, and then just cram their old shitty way of doing things back
into mongrel2, work that way for a while, and *then* realize they don't
need it.  That's always the progression, but before they had to follow
this progression without making hard to debug and support filters.

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] "middleware" and loopback

From:
Zed A. Shaw
Date:
2011-05-10 @ 22:13
On Tue, May 10, 2011 at 09:44:27PM +0200, Mathijs Kwik wrote:
> Hi Zed,
> 
> Well I wasn't saying mongrel2 should do the caching or something like that.
> I was suggesting that there can be a wide range of apps that are not
> "endpoints" that generate the full response themselves, but rather
> intercept requests (or responses) to change/enhance/check them some
> more.

I do that by just having a request go to a handler, who then sends it to
other handlers that need to it in the chain.  With mongrel2, the
receiver of a request doesn't have to be the responder, so you can do
this:

m2 -> [auth -> unzip -> confabulate -> query -> reply_html] -> m2

And each of those is just a handler.  In fact, in Tir this is directly
supported as Tasks, which are just 0mq messages sent async to a backend
from any handler, who then can respond how they want.

> In other words, apps need to be able to nest and forward (changed)
> requests and responses to each other.

So try the above idea where they do this nest/forward/signal to each
other through 0mq messaging.  It works surprisingly well and fast, and
ends up being much easier to work with than constantly reconfiguring the
front-end server, at the expense of small initial installs are more
complicated.

Look at the Tir code for insights though into how to make this easier.

> Like a before- and after filter.
> I'm sure you're familiar with the middleware concept that ruby's rack
> stack uses, this is exactly what I'm looking for.

Yes, very familiar since they were basically stolen from the Mongrel
Ruby API. :-)

Now that I've said the above, filters are coming in the next rounds of
development for things like this, but the goal with those is that they
be only for extending mongrel2 for things that should be done on the
edge or for weird uses like "inflight architecture upgrades".  Examples
are like, changing PHP's weird insistence on using GET parameters into
nice URLs instead of just rewriting your code, or working around Rails
inability to handle more than one request at a time reliably.

So in theory you could do that, but try the chained 0mq instead first.
You'll be surprised how easy it is in practice.

> Having to connect those "middleware" apps yourself largely defeats the
> purpose of mongrel2, even while 0mq is a big help.
>
> So it would be great if mongrel2's config could be used to put these
> stacks together.

So with this, it already does.  It's a database, so you can just add a
table for your own setup and then use it.  I do this in Tir a bit where
I just read the config.sqlite to configure it.  I'm imagining you'd just
make a table for these chains you want, then handlers wire themselves up
based on how the database is.

> One way to emulate this now is to have the "real" app listen on
> "myapp.internal" on mongrel2 and have a middleware app listen on
> myapp.com. After doing its thing, the middleware app can just use an
> http client to send the modified request to myapp.internal (on

Huh? Why would you use an http client?  Just use 0mq between the two.

> This however, is not very efficient. For one, the modified request has
> to be re-parsed when it arrives for myapp.internal. Also, the
> middleware app itself is responsible for an efficient event-loop (so
> it can accept new requests while waiting for the response of the first
> one). It would be great if mongrel2's internals can be exposed a
> little more, so these middleware apps can just let mongrel2 handle
> these dirty details.

The filters would allow this, but I really think you're under estimating
the speed of 0mq.  It looks like you're thinking about this as if you
had to use HTTP, but once the request is parsed out by Mongrel2 you can
just shove it around using 0mq as-is all you want.  Add to that the new
tnetstrings format and it's pretty damn fast.

Additionally, putting your whole app inside mongrel2 as a set of .so
linked in filters is a horrible deployment story.  Having to shutdown
whole front-end servers just to change a few headers or some HTML is
teh suck.

> I hope this makes my wishes a bit clearer.
> As stated, the behavior of ruby's rack stack is just the thing I need.

So, I think this is the entire disconnect in your thinking that I'd like
to correct.  Rack is *entirely* "request response", it's not async.
Because of this you have to do all this chaining and middleware config
ninjitsu just to process a request.  It's also brittle and doesn't
handle large scale deployments very well because, should you have to
alter the chain even a tiny bit, you're having to run around changing
server configs on both sides.

In Mongrel2, it doesn't care how receives and who sends its 0mq
messages, *and* it doesn't even care if the responses it receives are
complete.  You can stream out 1 byte sequences of 0mq messages from 100
handler backends to a browser and mongrel2 won't care.

I think until you actually try to grasp this you won't be able to
articulate a good feature request for this.  When I read what you're
asking for, it's effectively:

"I want to go backwards to a strict request/response chaining model."

Here's some examples from your feature list ideas:

> "this is not the real response, but rather a new request for app X"
> (headers/body netstrings, so no need to re-parse)

Create a ipc:// handler that takes all requests it receives, pulls the
raw 0mq message (no parsing needed), slaps this tag on it, then sends it
on to wherever it needs to go.  In fact, it doesn't have to parse
anything but the first few chars since we include the path and
everything right at the beginning.  No json or tnetstring parsing
required.

> And a special kind of request like:
> "this is the response from app X"

So, let's say the request from above bounces around between 10 different
0mq services, all dealing with it.  *Any* of the 10 services can abort
the request right there and send the response is if they are "the app".
In fact the concept of "an app" is sort of pointless because you can
carve your "app" up into as many pieces are you need or have the sanity
to maintain.

> Then you should be able to configure mongrel2 to "insert" apps between
> the request/response streams of other apps.

Create an ipc:/// that looks at the path, doesn't parse and then from
that shuttles the request to the first part of the chain.  No "insert"
needed, it just sends it where it needs to go, and then the response
goes directly to mongrel2 from whoever handled it.  If you need chains,
then you can use any number of simple patterns for work coordination to
pull this off.  This also has the added advantage that if the response
can take a while, this handler can send an initial "ok got it" response
and then the browser can hit a totally *different* url to receive the
reply just like long polling.

> - middleware apps that just modify a request
> They receive the incoming request, decide to answer themselves (for
> example a "hit" on a cache middleware), or to forward the (modified)
> request to app X.

I call these "inflight architecture upgrades".  Any time chains of
things are modifying the requests it's almost *always* because you're
trying to avoid changing broken architecture of application choices.
Things like URL rewriting, adding headers so Perl don't freak out,
converting GET requests to pretty URLs, etc.  This is the one place I'd
see filters coming into play rather than the above chained handlers.

I can see two ways people would go for this: 1) handlers just reparse
and modify the requests before sending it on, and probably would use
tnetstrings to avoid performance hits.  2) they write a filter and then
beat their programmers in the face until the filter isn't needed
anymore.  I really like option #2. :-)

> For that they use the special response.
> The listener id is forwarded to app X as well, so when app X responds,
> it responds directly to the original client

Yep, and all of that works with the existing 0mq handler setup.

So, sorry this is so long, but my response is these three points:

1.  You can already do most of this with 0mq and it's better, please go
try it out and then come back when you have a better understanding of
how the async nature of mongrel2 just really makes this stuff so much
easier.

2. Filters are coming so you'll be able to get this anyway, and they'll
probably be pretty easy to write if you know C.

3. I think you should really throw out what you know about web servers
based on Rack and middleware.  The reason middleware exists is because
CGI sucked so bad but was so ubiquitous that people had to work around
it.  To do that they made "middleware" that sat between apps and web
servers with CGI vars as the glue.  Mongrel2 just ditches all of that.
Once we started really using it we all realized that the middleware is
just pointless.  Mongrel2 already sends everything you need and 0mq is
already your "middleware", so why add another layer.  Existing
middleware is also *not* async so it can't handle a wide range of modern
HTTP needs.  Once you realize this there's this whole world that opens
up.

Hopefully that long email explains it, but feel free to do some more
research and/or wait for filters (probably 1.7) and then try to
implement what you were thinking about.

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] "middleware" and loopback

From:
Mathijs Kwik
Date:
2011-05-11 @ 06:56
Zed and Jason,

Thanks for your replies.
I must confess I've never actually used mongrel2 yet, so my question
and assumptions are probably based on ignorance.
I do see the enormous potential that mongrel2 will eventually give me
and I'm quite familiar with 0mq and its power for internal
communication between different pieces of an application.
However, using this power for web purposes is new to me, and my main
investigation as of yet was about how to "port" an old-style
request-reply application to mongrel2.
Specially, how to start splitting that monolithic beast into lots of
smaller pieces of functionality.
The first parts that came to mind were the different middleware layers
I'm using.
It indeed seems my thinking was a bit too conservative in trying to
keep the request-reply flow the way it is.
Indeed I need to just wire the pieces up myself and maybe start
thinking about unusual flows that now become possible, because there's
probably a lot of benefit to gain by thinking async there as well.

I didn't know about tir, but I've done some lua (ex wow addict :) so
I'll look into it as well to get some ideas and maybe even use it for
certain new parts.

So thanks for now, I need to investigate (and just try stuff) before
requesting changes :)

On Wed, May 11, 2011 at 12:13 AM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
> On Tue, May 10, 2011 at 09:44:27PM +0200, Mathijs Kwik wrote:
>> Hi Zed,
>>
>> Well I wasn't saying mongrel2 should do the caching or something like that.
>> I was suggesting that there can be a wide range of apps that are not
>> "endpoints" that generate the full response themselves, but rather
>> intercept requests (or responses) to change/enhance/check them some
>> more.
>
> I do that by just having a request go to a handler, who then sends it to
> other handlers that need to it in the chain.  With mongrel2, the
> receiver of a request doesn't have to be the responder, so you can do
> this:
>
> m2 -> [auth -> unzip -> confabulate -> query -> reply_html] -> m2
>
> And each of those is just a handler.  In fact, in Tir this is directly
> supported as Tasks, which are just 0mq messages sent async to a backend
> from any handler, who then can respond how they want.
>
>> In other words, apps need to be able to nest and forward (changed)
>> requests and responses to each other.
>
> So try the above idea where they do this nest/forward/signal to each
> other through 0mq messaging.  It works surprisingly well and fast, and
> ends up being much easier to work with than constantly reconfiguring the
> front-end server, at the expense of small initial installs are more
> complicated.
>
> Look at the Tir code for insights though into how to make this easier.
>
>> Like a before- and after filter.
>> I'm sure you're familiar with the middleware concept that ruby's rack
>> stack uses, this is exactly what I'm looking for.
>
> Yes, very familiar since they were basically stolen from the Mongrel
> Ruby API. :-)
>
> Now that I've said the above, filters are coming in the next rounds of
> development for things like this, but the goal with those is that they
> be only for extending mongrel2 for things that should be done on the
> edge or for weird uses like "inflight architecture upgrades".  Examples
> are like, changing PHP's weird insistence on using GET parameters into
> nice URLs instead of just rewriting your code, or working around Rails
> inability to handle more than one request at a time reliably.
>
> So in theory you could do that, but try the chained 0mq instead first.
> You'll be surprised how easy it is in practice.
>
>> Having to connect those "middleware" apps yourself largely defeats the
>> purpose of mongrel2, even while 0mq is a big help.
>>
>> So it would be great if mongrel2's config could be used to put these
>> stacks together.
>
> So with this, it already does.  It's a database, so you can just add a
> table for your own setup and then use it.  I do this in Tir a bit where
> I just read the config.sqlite to configure it.  I'm imagining you'd just
> make a table for these chains you want, then handlers wire themselves up
> based on how the database is.
>
>> One way to emulate this now is to have the "real" app listen on
>> "myapp.internal" on mongrel2 and have a middleware app listen on
>> myapp.com. After doing its thing, the middleware app can just use an
>> http client to send the modified request to myapp.internal (on
>
> Huh? Why would you use an http client?  Just use 0mq between the two.
>
>> This however, is not very efficient. For one, the modified request has
>> to be re-parsed when it arrives for myapp.internal. Also, the
>> middleware app itself is responsible for an efficient event-loop (so
>> it can accept new requests while waiting for the response of the first
>> one). It would be great if mongrel2's internals can be exposed a
>> little more, so these middleware apps can just let mongrel2 handle
>> these dirty details.
>
> The filters would allow this, but I really think you're under estimating
> the speed of 0mq.  It looks like you're thinking about this as if you
> had to use HTTP, but once the request is parsed out by Mongrel2 you can
> just shove it around using 0mq as-is all you want.  Add to that the new
> tnetstrings format and it's pretty damn fast.
>
> Additionally, putting your whole app inside mongrel2 as a set of .so
> linked in filters is a horrible deployment story.  Having to shutdown
> whole front-end servers just to change a few headers or some HTML is
> teh suck.
>
>> I hope this makes my wishes a bit clearer.
>> As stated, the behavior of ruby's rack stack is just the thing I need.
>
> So, I think this is the entire disconnect in your thinking that I'd like
> to correct.  Rack is *entirely* "request response", it's not async.
> Because of this you have to do all this chaining and middleware config
> ninjitsu just to process a request.  It's also brittle and doesn't
> handle large scale deployments very well because, should you have to
> alter the chain even a tiny bit, you're having to run around changing
> server configs on both sides.
>
> In Mongrel2, it doesn't care how receives and who sends its 0mq
> messages, *and* it doesn't even care if the responses it receives are
> complete.  You can stream out 1 byte sequences of 0mq messages from 100
> handler backends to a browser and mongrel2 won't care.
>
> I think until you actually try to grasp this you won't be able to
> articulate a good feature request for this.  When I read what you're
> asking for, it's effectively:
>
> "I want to go backwards to a strict request/response chaining model."
>
> Here's some examples from your feature list ideas:
>
>> "this is not the real response, but rather a new request for app X"
>> (headers/body netstrings, so no need to re-parse)
>
> Create a ipc:// handler that takes all requests it receives, pulls the
> raw 0mq message (no parsing needed), slaps this tag on it, then sends it
> on to wherever it needs to go.  In fact, it doesn't have to parse
> anything but the first few chars since we include the path and
> everything right at the beginning.  No json or tnetstring parsing
> required.
>
>> And a special kind of request like:
>> "this is the response from app X"
>
> So, let's say the request from above bounces around between 10 different
> 0mq services, all dealing with it.  *Any* of the 10 services can abort
> the request right there and send the response is if they are "the app".
> In fact the concept of "an app" is sort of pointless because you can
> carve your "app" up into as many pieces are you need or have the sanity
> to maintain.
>
>> Then you should be able to configure mongrel2 to "insert" apps between
>> the request/response streams of other apps.
>
> Create an ipc:/// that looks at the path, doesn't parse and then from
> that shuttles the request to the first part of the chain.  No "insert"
> needed, it just sends it where it needs to go, and then the response
> goes directly to mongrel2 from whoever handled it.  If you need chains,
> then you can use any number of simple patterns for work coordination to
> pull this off.  This also has the added advantage that if the response
> can take a while, this handler can send an initial "ok got it" response
> and then the browser can hit a totally *different* url to receive the
> reply just like long polling.
>
>> - middleware apps that just modify a request
>> They receive the incoming request, decide to answer themselves (for
>> example a "hit" on a cache middleware), or to forward the (modified)
>> request to app X.
>
> I call these "inflight architecture upgrades".  Any time chains of
> things are modifying the requests it's almost *always* because you're
> trying to avoid changing broken architecture of application choices.
> Things like URL rewriting, adding headers so Perl don't freak out,
> converting GET requests to pretty URLs, etc.  This is the one place I'd
> see filters coming into play rather than the above chained handlers.
>
> I can see two ways people would go for this: 1) handlers just reparse
> and modify the requests before sending it on, and probably would use
> tnetstrings to avoid performance hits.  2) they write a filter and then
> beat their programmers in the face until the filter isn't needed
> anymore.  I really like option #2. :-)
>
>> For that they use the special response.
>> The listener id is forwarded to app X as well, so when app X responds,
>> it responds directly to the original client
>
> Yep, and all of that works with the existing 0mq handler setup.
>
> So, sorry this is so long, but my response is these three points:
>
> 1.  You can already do most of this with 0mq and it's better, please go
> try it out and then come back when you have a better understanding of
> how the async nature of mongrel2 just really makes this stuff so much
> easier.
>
> 2. Filters are coming so you'll be able to get this anyway, and they'll
> probably be pretty easy to write if you know C.
>
> 3. I think you should really throw out what you know about web servers
> based on Rack and middleware.  The reason middleware exists is because
> CGI sucked so bad but was so ubiquitous that people had to work around
> it.  To do that they made "middleware" that sat between apps and web
> servers with CGI vars as the glue.  Mongrel2 just ditches all of that.
> Once we started really using it we all realized that the middleware is
> just pointless.  Mongrel2 already sends everything you need and 0mq is
> already your "middleware", so why add another layer.  Existing
> middleware is also *not* async so it can't handle a wide range of modern
> HTTP needs.  Once you realize this there's this whole world that opens
> up.
>
> Hopefully that long email explains it, but feel free to do some more
> research and/or wait for filters (probably 1.7) and then try to
> implement what you were thinking about.
>
> --
> Zed A. Shaw
> http://zedshaw.com/
>