Best way to cache a response in Sinatra?
Personally, I prefer to use redis for this type of things over memcached. I have an app that I use redis in pretty extensively, using it in a similar way to what you described. If I make a call that is not cached, page load time is upwards of 5 seconds, with redis, the load time drops to around 0.3 seconds. You can set an expires time as well, which can be changed quite easily. I would do something like this to retrieve the data from the cache.
require 'redis'
get '/my_data/:id' do
redis = Redis.new
if redis[params[:id]]
send_file redis[params[:id]], :type => 'application/json'
end
end
Then when you wanted to save the data to the cache, perhaps something like this:
require 'redis'
redis = Redis.new
<make API calls here and build your JSON>
redis[id] = json
redis.expire(id, 3600*24*5)
Sinatra - Setting Cache-Control Headers via config.ru
Here's how to set long expiry headers for static assets, and an arbitrary expiry header for you main content on Heroku:
gemfile:
gem 'rack-contrib'
config.ru:
require 'rack/contrib'
get '*.html' do |page|
# whatever code you need to serve up your main pages
# goes here... use Rack::File I guess.
page
end
# Set content headers for that content...
before do
expires 5001, :public, :must_revalidate
end
# Assets in /static/stylesheets (domain.com/stylesheets)
# are served by Rack StaticCache, with a default 2 year expiry.
use Rack::StaticCache, :urls => ["/stylesheets"], :root => Dir.pwd + '/static'
run Sinatra::Application
By default that will give you a 2 year expiry for content listed in the array of urls (static/stylesheets, static/images etc.).
You have to move from /public to /static because otherwise you are unnecessarily fighting with Heroku's nginx config (the right place to apply these sorts of settings really...).
I know you said you're trying to not use Rack Contrib but that makes no sense. There's no harm in using a tiny 90 line library to do this https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/static_cache.rb.
The "right" way would be to host static content on an environment where you can configure nginx, and the second best way is renaming your static file path so heroku ignores it, and use rack static to serve static files with the headers you want.
--
Also to be clear, simply renaming your public folder to something else will allow you to do this via routes, and the normal Sinatra expires function. But I'd use StaticCache because it's less verbose. (The real issue is Heroku doesn't let nginx talk to your app for requests to public/, I believe.)
How to set HTTP response (cache) headers in a Sinatra app hosted on Heroku
Apart from the fact that I wouldn't get through the Sinatra stack just to serve static files, you'd call
cache_control :public, max_age: 60
to cache for a minute. cache_control
is a helper that comes with Sinatra.
Otherwise, I'd suggest you have a look at http://www.sinatrarb.com/configuration.html to see how Sinatra is set up so you don't have do deal with serving static files.
Hope this helps.
edit: I just saw you were explicitly asking for the Expires
header. I'm not sure, but that should be fairly the same way as Cache-Control
. Sorry for the confusion
Caching a redirect to a static image in Sinatra
You set the Cache-Control on a per route basis:
get '/stream/:service/:stream_id.png' do
# Building image_url omitted
response['Cache-Control'] = "public, max-age=0, must-revalidate"
redirect image_url
end
Sinatra app with unicorn and memcached should return 304 codes for cache hits?
Unicorn cannot know how your application handles caching. Therefore it cannot set etags for you.
Like Rajesh said, 304 is about browser cache.
You will have to generate an Etag hash in your app and then send it to the browser (via header).
According to this post browsers have support for etags : Browser support for eTags etags.
Here is the official doc on 304 : http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
Edit :
Take a look here to implement it with sinatra :
http://www.sinatrarb.com/intro#Cache%20Control
http://opensoul.org/blog/archives/2011/01/29/etags-with-memcached/
How can I control caching for static assets when using Sinatra?
You can use the static_cache_control
setting to set the Cache-Control
header for static files served by Sinatra:
set :static_cache_control, [:public, max_age: 60 * 60 * 24 * 365]
Note you need to use an explicit array [...]
.
Also this will apply to all files in the public
directory, i.e. you can’t specify different headers for css and javascript files.
(If you’re not using Heroku and are using Apache or Nginx to serve static files then this won’t work, in that case you’d need to configure your webserver separately).
Sinatra cache control is not working
Which file you add max-age header?
If it's JavaScript or CSS file, please try to build files with Sinatra-assetpack.
Files built are located in under 'public' directory.
Please see the following, written how to build.
http://ricostacruz.com/sinatra-assetpack/#need_to_build_the_files
sinatra-cors not responding with 200 when using middleware
The issue was related to an error in my middleware (Error module was not included in the source, and the default configuration of Rack caused errors not to be displayed)
Related Topics
Ruby Strftime: Month Without Leading Zero
Testing Actionmailer Multipart Emails(Text and HTML Version) with Rspec
Best Place to Store Model Specific Constants in Rails 3.1
Resque Multiple Workers in Development Mode
How to Get a List of All Tags While Using the Gem 'Acts-As-Taggable-On' in Rails (Not the Counts)
How to Use Define_Method Inside Initialize()
How to Test 'Create' Controller Actions
Ruby Unable to Parse a CSV File: CSV::Malformedcsverror (Illegal Quoting in Line 1.)
How to Reference an Embedded Document in Mongoid
Specifying a Layout and a Template in a Standalone (Not Rails) Ruby App, Using Slim or Haml
Ubuntu 12 - How to Install Ruby and Rails Correctly
How to Structure a Layout Template in Haml
How to Convert an Existing Rails 3 Application into an Engine
Code to Generate Gaussian (Normally Distributed) Random Numbers in Ruby