Note that there are some explanatory texts on larger screens.

plurals
  1. PORails/Dragonfly/Apache - Rack::Cache - how to use X-Sendfile?
    primarykey
    data
    text
    <p>I'm using <a href="https://github.com/markevans/dragonfly" rel="nofollow">Dragonfly</a> to serve processed images for my Rails app. Dragonfly relies on <a href="https://github.com/rtomayko/rack-cache" rel="nofollow">Rack::Cache</a> for future visits to those processed images, so that <a href="http://markevans.github.com/dragonfly/file.Caching.html" rel="nofollow">Dragonfly won't have to process those images again</a> and again, thus wasting CPU time.</p> <p>My problem starts here: if I'm right that sending a file via Rack::Cache still busies a Rails process, then viewing a page of 30 images, even if these images have a small file size, will tie up the Rails processes pretty quickly. If a couple more visitors come to see that page, then they will experience very slow response times. How do I get these files served via X-Sendfile?</p> <p>I've set the following in <code>production.rb</code>, but I know these are for the assets from Rails, not the Dragonfly files:</p> <pre><code>config.serve_static_assets = false config.action_dispatch.x_sendfile_header = "X-Sendfile" </code></pre> <p>I know that Rack::Cache somehow supports X-Sendfile (probably through <a href="https://github.com/rack/rack/blob/master/lib/rack/sendfile.rb" rel="nofollow">Rack::Sendfile</a>) because it <a href="https://github.com/rtomayko/rack-cache/blob/master/test/entitystore_test.rb#L124" rel="nofollow">produces a body that responds to <code>#to_path</code></a>. However, I don't know how to enable this. When I check files that come from Rack::Cache, I don't see any X-Sendfile information:</p> <pre><code>Date: Wed, 02 Nov 2011 11:38:28 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.9 Content-Disposition: filename="2.JPG" Cache-Control: public, max-age=31536000 Etag: "3174d486e4df2e78a5ff9174cacbede5787d4660" X-Content-Digest: c174408eda6e689998a40db0aef4cdd2aedb3b6c Age: 28315 X-Rack-Cache: fresh Content-Length: 22377 Status: 200 Content-Type: image/jpeg </code></pre> <p>I know, based on <a href="https://github.com/rails/rails/issues/1822" rel="nofollow">posts around the net</a>, that I'm supposed to see something like:</p> <pre><code>X-Sendfile: /path/to/file </code></pre> <p>In the end I don't know if its Dragonfly or Rack::Cache (or both) that I have to configure. <strong>How do I get either Dragonfly and/or Rack::Cache to serve files via X-Sendfile</strong>?</p> <p>Info about my setup:</p> <ul> <li>Rails 3.1.1</li> <li>Passenger 3.0.9</li> <li>CentOS</li> <li>Sendfile module is installed, as far as I know. I have <code>XSendFile On</code> and <code>XSendFilePath /path/to/app</code> specified in my virtualhost configuration, and Apache doesn't complain about the directive <code>XSendFile</code> not existing.</li> </ul> <p>Thanks!</p> <p><strong>UPDATE Nov 6, 2011</strong></p> <p>Based on <a href="https://groups.google.com/d/topic/rack-cache/goQ6uAnVGL8/discussion" rel="nofollow">this old update</a>, as long as <code>Rack::Sendfile</code> is placed in front of <code>Rack::Cache</code>, then X-Sendfile will be used. I did that, and this is how <a href="https://gist.github.com/1339975" rel="nofollow">my middleware looks like</a>. The files, however, <a href="https://gist.github.com/1339985" rel="nofollow">still don't have the X-Sendfile tag</a>. Again, I don't know if that is a sure-fire way of determining if X-Sendfile is enabled, so I checked the Passenger queue. It seems that the queue is greatly encumbered when I visit a page.</p> <p><strong>UPDATE Nov 7, 2011</strong></p> <p>It seems this is purely a Rack::Cache and Rails 3.1 issue. While Rack::Cache supports the use of X-Sendfile through Rack::Sendfile (like I mentioned above, Rack::Cache, when using the <a href="https://github.com/rtomayko/rack-cache/blob/master/lib/rack/cache/entitystore.rb#L83" rel="nofollow">Disk</a> EntityStore since that responds_to <code>to_path</code> since the <a href="https://github.com/rtomayko/rack-cache/blob/master/lib/rack/cache/entitystore.rb#L105" rel="nofollow">body it returns is a subclass of File</a>), Rails 3.1 uses its own storage solution. Rails 3.1 uses <a href="https://github.com/rails/rails/blob/3-1-stable/activesupport/lib/active_support/cache/file_store.rb#L81" rel="nofollow">ActiveSupport::Cache::FileStore</a>, which is set by default, if you don't specify anything in your <code>production.rb</code> file.</p> <p>The problem with FileStore is that the body it returns, to be part of the response to be sent upstream, because that body doesn't respond to <code>to_path</code>. The body is an instance of <a href="https://github.com/rails/rails/blob/3-1-stable/activesupport/lib/active_support/cache.rb#L532" rel="nofollow">ActiveSupport::Cache::Entry</a>. You can see <a href="https://github.com/rails/rails/blob/3-1-stable/activesupport/lib/active_support/cache/file_store.rb#L81" rel="nofollow">here</a> that when the FileStore is asked to read a cached file, it reads it via <code>File.open('/path/to/file') {|f| Marshal.load(f) }</code> which returns an instance of Entry. The value that ultimately gets passed upstream and back to the client, is <a href="https://github.com/rails/rails/blob/3-1-stable/activesupport/lib/active_support/cache.rb#L324" rel="nofollow">Entry#value</a>.</p> <p><strong>My questions</strong></p> <p>To help me decide whether I should patch this, or to get Rails to use Rack::Cache's own Disk store instead, I have some questions:</p> <ol> <li>What's the reason Rack::Cache's own storage solutions weren't used for Rails 3.1? Why does Rails have its own?</li> <li>Is there a reason Marshal is used? Is there a reason that a bytestream of data should be sent back instead?</li> </ol> <p>I got in deeper than I usually go, and will be surprised if I understood things correctly. I hope to find an answer!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload