Date post: | 13-Apr-2017 |
Category: |
Software |
Upload: | brad-johnson |
View: | 52 times |
Download: | 0 times |
Agenda1.Why do we need to do this? 2.What is a Conditional GET request? 3.How do we do it? 4.How does it work?
The Problem:We build apps quickly. Apps consume a lot
of data (JSON in this example). Often, a lot of the data doesn’t change very often, but it’s easier to just fetch all the things all the time,
because cache invalidation is hard.
Then, one day we need to scale. And one of the
strategies we decide to use is to cache some responses.
Problems• Page and action cacheing have been
moved from Rails 4 into gems • Fragment cacheing requires memory,
and often things like Redis or memcached.
• Buggy
Conditional requestsPart of the HTTP standard that
allows browsers to ask servers if anything has changed, or not.
Request headers can be used by both the client and the server to determine if any new data is present. If no new data is
present, the server can return a 304. If new data is available, it can render the new data.
Time-Basedclass PokemonsController < ApplicationController
def index pokemons = Pokemon.all.includes(:pokemon_type) expires_in 1.minute render json: pokemons endend
Etagsclass PokemonsController < ApplicationController
def index pokemons = Pokemon.all.includes(:pokemon_type) if stale? etag: pokemons render json: pokemons end endend
Last Modifiedclass PokemonsController < ApplicationController
def index pokemons = Pokemon.all.includes(:pokemon_type) if stale? last_modified: pokemons.maximum(:updated_at) render json: pokemons end endend
Last Modified + Etagclass PokemonsController < ApplicationController
def index pokemons = Pokemon.all.includes(:pokemon_type) if stale? pokemons render json: pokemons end endend
#stale?# rails/actionpack/lib/action_controller/metal/conditional_get.rb
def stale?(object = nil, **freshness_kwargs) fresh_when(object, **freshness_kwargs) !request.fresh?(response)end
#fresh_when?# rails/actionpack/lib/action_controller/metal/conditional_get.rb
def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, template: nil)
weak_etag ||= etag || object unless strong_etag last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at)
if strong_etag response.strong_etag = combine_etags strong_etag, last_modified: last_modified, public: public, template: template elsif weak_etag || template response.weak_etag = combine_etags weak_etag, last_modified: last_modified, public: public, template: template end
response.last_modified = last_modified if last_modified response.cache_control[:public] = true if public
head :not_modified if request.fresh?(response)end
#request_fresh?# rails/actionpack/lib/action_dispatch/http/cache.rb
def fresh?(response) last_modified = if_modified_since etag = if_none_match
return false unless last_modified || etag
success = true success &&= not_modified?(response.last_modified) if last_modified success &&= etag_matches?(response.etag) if etag successend