Page caching in rails application running under non-root context.

#1
Hi all,
I have several rails apps running under a single vhost under contexts like '/v1', '/v2', '/v3' - all work fine with no page caching enabled.

When I enable page caching for some actions, rails is correctly generating the cache files in <RAILS_ROOT>/public (or whatever dir I set config.action_controller.page_cache_directory to) but Litespeed isn't serving the cached files - it always dispatches the request to the rails app (via dispatch.lsapi)

Enabling litespeed debug, I'm noticing the following when I request a URL that I know has been cached (I can see the cache file on the server e.g. <RAILS_ROOT>/v1/groups.atom)

GET /v1/groups.atom HTTP/1.1
2008-08-07 17:17:34.187 [INFO] [127.0.0.1:55487-0#aehso] [REWRITE] Rule: Match '/v1/groups.atom' with pattern '^(.*)/$', result: -1
2008-08-07 17:17:34.187 [INFO] [127.0.0.1:55487-0#aehso] [REWRITE] Rule: Match '/v1/groups.atom' with pattern '^([^.]+)$', result: -1
2008-08-07 17:17:34.187 [DEBUG] [127.0.0.1:55487-0#aehso] Find context with URI: [/v1/], location: [/trunk/rails1/public/]
2008-08-07 17:17:34.187 [DEBUG] [127.0.0.1:55487-0#aehso] File not found [/trunk/rails1/public/groups.atom]
2008-08-07 17:17:34.187 [DEBUG] [127.0.0.1:55487-0#aehso] processContextPath() return 25
2008-08-07 17:17:34.187 [DEBUG] [127.0.0.1:55487-0#aehso] processNewReq() return 25.
2008-08-07 17:17:34.187 [DEBUG] [127.0.0.1:55487-0#aehso] HttpConnection::sendHttpError(),code=404 Not Found
2008-08-07 17:17:34.187 [DEBUG] [127.0.0.1:55487-0#aehso] redirect to:
URI=[/v1/dispatch.lsapi],
QueryString=[]

Some quick env parms for context:
VH_ROOT=/trunk/rails1 (RAILS_ROOT)
DOC_ROOT=/trunk/rails1/public
Rails Context '/v1' - Location = $VH_ROOT

The cached file in the above instance is actually in /trunk/rails1/public/v1/groups.atom

I'm trying to find a way to fix this but I've had no luck.
- the Vhost DOC_ROOT seems to be ignored, no matter what I set it to.
- I can't change the context root to '/' as we have other rails apps running under different contexts ('/v1', '/v2', '/v3' etc)
- I can't hack (rewrite) the something like /v1/v1/groups.atom as if the cached file doesn't exist, the lsapi redirect still needs to work.

lsws really seems to be hardcoded to appending 'public' onto the url context location dir and then stripping off the url context prefix before looking for the file. Ideally it would look in DOC_ROOT (which I could perhaps set to $VH_ROOT/pubic/v1) but that doesn't seem to happen at all for me.

Any suggestions?

cheers,

John.
 
#4
Why not just cache the result under /trunk/rails1/public/?
Rails is creating the cached files under /trunk/rails1/public . For example, when generating '/v1/groups.atom', rails places the cached file at /trunk/rails1/public/v1/groups.atom. (note, the rails app is 'aware' of the 'v1/' part of the url path - it is prefixed to all rails routes)

The problem here is when litespeed checks to see if the cached file exists (prior to dispatching via lsapi), it is looking for a file called /trunk/rails1/public/groups.atom - note the 'v1/' part of the path is missing. It fails to find it because it is looking in the wrong dir so it always invokes the rails application.
 
#5
If you run the app under "/v1" URL, you'd better not using it as the document root for the vhost.
Is the document root actually used at all for these requests (when the context is a rails context)? I've tried tinkering with it, setting it to various filesystem paths (/trunk/app/public, trunk/app/public/v1 etc) but it seems to have no effect on the request dispatching at all...
 

mistwang

LiteSpeed Staff
#6
Can you make it cache the result to /trunk/rails1/public/groups.atom instead of /trunk/rails1/public/v1/groups.atom?
Since /trunk/rails1/public/ is mapped to URL "/v1/" already, LSWS won't add "/v1" to the path again.

Another possible solution is to configure the Rails app manually instead of using Rails context, this way, you can customize the rewrite rules used to dispatch the request.
 

mistwang

LiteSpeed Staff
#7
Another possible solution is to add a rewrite rule to rails context to rewrite url "/v1/groups.atom" to "/v1/v1/groups.atom" if file "/trunk/rails1/public/v1/groups.atom" exists.
 
#8
Can you make it cache the result to /trunk/rails1/public/groups.atom instead of /trunk/rails1/public/v1/groups.atom?
Since /trunk/rails1/public/ is mapped to URL "/v1/" already, LSWS won't add "/v1" to the path again.
I don't think this is possible as the rails caches_page: impl uses the routes config to figure out the correct path for the resource. Also, this is only one example - i'll likely have many cachable resources in each context.

Another possible solution is to configure the Rails app manually instead of using Rails context, this way, you can customize the rewrite rules used to dispatch the request.
I'd probably do this, if I knew how :) Would I loose anything by not using the built in rails context (i'm thinking about other rails pool config params specifically)

Thanks,

John.
 
#9
Another possible solution is to add a rewrite rule to rails context to rewrite url "/v1/groups.atom" to "/v1/v1/groups.atom" if file "/trunk/rails1/public/v1/groups.atom" exists.
Hmmm, it is a bit of a hack isn't it - I'd be concerned that every request will end up having to go through the same hoop. (I'm also not that proficient at writing apache rewrite rules)

One a more general note though, do you think this is a bug or am I wrong to assume this should work? i.e.
- should litespeed be stripping off the leading context from the path before looking on the filesystem for the static resource?
- is the 'public' part of the path it is checking hardcoded in some way? (it isn't anywhere in my config)

Thanks for the feedback so far, great support...

John.
 

mistwang

LiteSpeed Staff
#10
That is not a LiteSpeed bug, the behavior is as designed and follow that of Apache, the rails context does some magic behind the scene to make rails configuration as simple as possible, but it may not work perfectly for all situations. In your case, you may have to use rewrite rule to fix it up, it is the easiest solution.

"public" is added on top of RAILS_ROOT for all rails contexts automatically, as it is how Rails organize things.
 
#11
"public" is added on top of RAILS_ROOT for all rails contexts automatically, as it is how Rails organize things.
I think that's the crux of the problem. If litespeed allowed that behavior to be configurable (via a rails context config option, defaulting to 'public') then I'd be able to manually set it to 'public/v1' and I suspect that would get it all working. Any chance of adding such a config option for future releases?

Meanwhile, I'll try adding in the /v1/v1 rewrite (if the file exists) and run with that...

Thanks again, great server btw!

John.
 
Top