I have a Rails 3.2 application, where the client side polls a resource in the server for updates. This resource is not an asset, but dynamic content.
The implementation strategy i chose is a Conditional Get via the fresh_when directive:
fresh_when(:etag => @etag, :public => false ) #it's a private resource, requires auth etc
So, when the resource is still fresh (request 'If-Not-Modified' header equals the resource current ETag), the server only returns a 304 header.
Started GET "/news/4fe13e74aa5e7d3d70000001"
Processing by NewsController#show as JSON
Parameters: {"id"=>"4fe13e74aa5e7d3d70000001"}
Completed 304 Not Modified
When the resource is no longer fresh, then we have status 200 and the most recent version of the resource in the response body:
Started GET "/news/4fe13e74aa5e7d3d70000001"
Processing by NewsController#show as JSON
Parameters: {"id"=>"4fe13e74aa5e7d3d70000001"}
Rendered news/show.json.rabl (8.1ms)
Completed 200 OK in 14ms
At the development environment this works perfectly. The problem lies in the production environment (Heroku Cedar Stack). In this scenario, the responses are always 200 with the full object representation in the body:
2012-08-03T21:44:33+00:00 heroku[router]: GET blah.com/news/4fa43b428b91cd0001000002 dyno=web.1 queue=0 wait=0ms service=22ms status=200 bytes=2105
2012-08-03T21:44:33+00:00 app[web.1]: Started GET "/news/4fa43b428b91cd0001000002"
2012-08-03T21:44:33+00:00 app[web.1]: cache: [GET /news/4fa43b428b91cd0001000002] miss
2012-08-03T21:44:33+00:00 heroku[nginx]: 187.38.19.138 - - [03/Aug/2012:21:44:33 +0000] "GET /news/4fa43b428b91cd0001000002 HTTP/1.1" 200 665 "http://www.bla.com/news/4fa43b428b91cd0001000002" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.57 Safari/537.1"
From what it looks, this request isn't reaching the Rails Controller (where the freshness is actually evaluated), but is passing through heroku's router and caching layers.
What i've tried so far:
- Double checked Rails (3.2.1) and Thin (1.3.1) versions in both environments.
- Setting 'config.action_controller.perform_caching = false'
- Removing Rack::Cache middleware (config.middleware.delete Rack::Cache)
The reason i don't want those redundant responses is because it bombs the client side app with unneeded object refreshes, causing a serious performance hit to the end user. When only a 302 header is returned from the server, the client-side javascript just sleeps for a while before polling again.
Thanks