3.1: Preventing assets from being cached in Rails.cache/Rack::Cache #2468
Comments
After some research and experimentation, I've ended up doing this in my config/application.rb for now: if !Rails.env.development? && !Rails.env.test?
config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: 'public'
end I've have a more detailed explanation in a blog post and also StackOverflow. |
I'm having/seeing the same issue. I would say this is a huge problem. |
How do i check the list of assets cached in the Rails cache? |
The proposed workaround seems to conflict with Dragonfly. Plus not only are these assets being needlessly cached but it seems to prevent the assets from even being found at all in some instances. I haven't worked out exactly what conditions are causing this but I am seeing "The page you were looking for doesn't exist" for assets that are blatantly present under public/assets. |
+1 for fixing this. It's extremely strange (and quite unnecessary) to store static assets in the application cache by default. |
Rack Cache should be configured differently for entity storage vs meta storage. Rack::Cache has two different storage areas: meta and entity stores. The metastore keeps high level information about each cache entry including HTTP request and response headers. This area stores small chunks of data that is accessed at a high frequency. The entitystore caches the response body content which can be a relatively large amount of data though it is accessed less frequently than the metastore The below configuration caches the metastore info in memcached but the actual body of the assets to the file system. Using memcached gem: config.action_dispatch.rack_cache = {
:metastore => 'memcached://localhost:11211/meta',
:entitystore => 'file:tmp/cache/rack/body',
:allow_reload => false
} Using dalli gem config.action_dispatch.rack_cache = {
:metastore => Dalli::Client.new,
:entitystore => 'file:tmp/cache/rack/body',
:allow_reload => false
} By the way this configuration is the recommendation for Heroku: |
|
@twinturbo I meant that indirectly. config.action_controller.perform_caching = true This enables action/page/fragment caching and also turns on It looks like you can also disable config.action_dispatch.rack_cache = nil but I didn't want to disable |
@kamui +1 for fixing this - I have been seeing Rails make copies of compiled assets in its cache folder in production, and at time these actually get corrupted somehow, so the wrong files get served - I'm guessing some sort of threadsafe issue, but I don't see any benefit in trying to track it down since making a file cache of files is just wasting resources. Your fix to force them to be served with Rack::Static appears to work perfectly An out of the box rails app in production is taking JS/CSS/image files and copying them into a file-based "cache". It seems like this should be disabled |
I don't consider this a bug in Rails, for several reasons:
This situation could be improved by documentation. It would be good to have something in the asset pipeline guide along the lines of "if your assets are being served by a CDN, ensure they don't stick around in your HTTP cache forever (by LRU eviction, configuration, etc)". |
I've written some documentation and put it in docrails here: https://github.com/lifo/docrails/commit/e85cb2d3bb95ae5cf2f524ffc6828fd40723c83e |
Nice one Steve. Think we can close this then. |
Thanks for the note! |
Just a note where one might get concerned is when your asset that is being cached is > 1MB. Memcached can only hold 1MB of cached data in a bucket. This will lead to all sorts of hilarity. |
@seigel The default maximum item size in Memcached is 1 MB. Since Memcached 1.4.2, this maximum item size can be configured and increased. E.g.
|
Yup. Just Putting the comment in there for the person who is maybe using a stock deploy or a service from Heroku or something and is finding that their app is crashing and they have no idea why. That is how we got to this point :) |
I have a Rails 3.1 app on Heroku that uses Cloudflare as a CDN. Cloudflare is a DNS based CDN, so you use their DNS servers for your domain. When a static asset is first requested, Cloudflare requests it from your web app, caches the file in it's CDN and then subsequent requests get served from the CDN. It's similar to how Amazon Cloudfront works, except that your asset host remains your app's host instead of some other domain name.
The issue arrises when you use:
config.action_controller.perform_caching = true
In 3.1, Rack::Cache seems to automatically use your config.cache_store to store assets/html fragments. Since Cloudflare is handling my asset caching, I want to stop Rack::Cache from caching assets to Rails.cache. In my case, I'm using redis-store, so my RedisToGo instance is being filled up quickly with static assets from Rack::Cache. This is kind of redundant since my CDN is going to be serving a majority of these requests. The few asset requests that Rails should get should be from Cloudflare, so it's fine if Rails serves this directly from the precompiled assets instead of from the Rails.cache.
I've considered disabling the Rack::Cache middleware, but then I lose out on page/action/fragment controller caching. I've tried setting my config.static_cache_control to private or no-cache, but no-cache would also prevent user browers from caching the assets and both still store assets in the cache.
I'm at a loss here. For now I've increased my RedisToGo instance, but that's not a good long term strategy.
The text was updated successfully, but these errors were encountered: