diff --git a/ubiquo_design/app/models/page.rb b/ubiquo_design/app/models/page.rb index 9a93189b..9befb1b8 100644 --- a/ubiquo_design/app/models/page.rb +++ b/ubiquo_design/app/models/page.rb @@ -125,7 +125,7 @@ def publish :published_id => published_page.id ) - expire_varnish if Rails.env.production? + UbiquoDesign.cache_manager.expire_page(self) if Rails.env.production? end return true rescue Exception => e @@ -157,17 +157,6 @@ def expire_varnish true end - def varnish_request(url) - Rails.logger.warn "PURGING #{url}" - puts "PURGING #{url}" - begin - http = Net::HTTP.new(VARNISH_SERVER) - http.send_request('BAN', url) - rescue - '' - end - end - # Returns true if the page has been published def published? published_id diff --git a/ubiquo_design/lib/ubiquo_design/cache_managers/base.rb b/ubiquo_design/lib/ubiquo_design/cache_managers/base.rb index 134e2760..94be1616 100644 --- a/ubiquo_design/lib/ubiquo_design/cache_managers/base.rb +++ b/ubiquo_design/lib/ubiquo_design/cache_managers/base.rb @@ -286,21 +286,6 @@ def with_instance_content(widget, options) if options[:current_model].present? && options[:current_model].to_s != key.to_s next end - if val[:identifier].is_a?(Hash) - if options[:scope].respond_to?(:params) - true_identifier = val[:identifier].keys.first - else - true_identifier = val[:identifier].values.first - end - elsif val[:identifier].is_a?(Array) - if options[:scope].respond_to?(:params) - true_identifier = val[:identifier].first - else - true_identifier = val[:identifier].last - end - else - true_identifier = val[:identifier] - end p_i = key.to_s + '_' p_i += process_params(val, options) diff --git a/ubiquo_design/lib/ubiquo_design/cache_managers/varnish.rb b/ubiquo_design/lib/ubiquo_design/cache_managers/varnish.rb new file mode 100644 index 00000000..4bf71fc6 --- /dev/null +++ b/ubiquo_design/lib/ubiquo_design/cache_managers/varnish.rb @@ -0,0 +1,102 @@ +module UbiquoDesign + module CacheManagers + # Varnish implementation for the cache manager + class Varnish < UbiquoDesign::CacheManagers::Base + +# CONFIG = Ubiquo::Config.context(:ubiquo_design).get(:varnish) + + class << self + + # This method is called when rendering +page+ and returns a hash where + # the keys are the ids of the page widgets that are esi widgets, + # and the value is an esi:include tag + def multi_get(page, options = {}) + {}.tap do |widgets_by_id| + request = options[:scope].request + page.blocks.each do |block| + block.real_block.widgets.each do |widget| + if esi_widget?(widget) + new_params = request.query_parameters.merge('widget' => widget.id) + esi_url = request.url.gsub("?#{request.query_string}", '') + "?#{new_params.to_query}" + widgets_by_id[widget.id] = "" + end + end + end + end + end + + # Caches the content of a widget + # Simply return, since the real caching is done by Varnish when the request is finished + def cache(widget_id, contents, options = {}); end + + # Returns true if the widget is an esi widget + def esi_widget?(widget) + # TODO + defined? ESI_ENABLED + end + + # Expires the applicable content of a widget given its id + # This means all the urls where the widget is cached + # +widget+ is a Widget instance + def expire(widget) + Rails.logger.debug "-- Expiring Varnish --" + + # We ban all the urls of the related page that also contain the widget id + # e.g. /url/of/page?param=4&widget=42 + ban_url = Regexp.escape(widget.page.url + "?") + ".*widget=#{widget.id}" + + # And we also ban all the urls that do not contain the widget param + # (i.e. the "full page", which can have different representations if + # it has different params). + # This is needed since else the esi fragment would be new, + # but the page would still be cached. + # The other cached pages with the "widget" param are in fact + # other widgets of this page, which have not been modified + # e.g. /url/of/page?param=4 (this will be expired because !~) + ban_negative_url = Regexp.escape(widget.page.url + '?') + ".*widget=" + + # Now do the real job. This is the correct order to avoid recaching old data + ban(ban_url) + ban_negative(ban_negative_url) + end + + # Expires a +page+, with all its possibles urls and params + def expire_page(page) + # We cannot simply ban url_page* since url_page could be a segment of + # another page, so: + # ban the url_page with params + ban(Regexp.escape(page.url + "?")) + # ban the exact page url, with or without trailing slash + ban(Regexp.escape(page.url) + "[\/]?$") + end + + protected + + # Bans all urls that match +url+ (which is interpreted as a regexp) + def ban(url) + varnish_request('BAN', url) + end + + # Bans all urls not matching +url+ + def ban_negative(url) + varnish_request('BAN_NEG', url) + end + + # removes the widget content from the store + def varnish_request method, url + Rails.logger.debug "Varnish #{method} request for url #{url}" + # TODO deal with multiple servers + begin + http = Net::HTTP.new(VARNISH_SERVER, VARNISH_PORT) + http.set_debug_output($stderr) # TODO temporal + http.send_request(method, url) + rescue + Rails.logger.warn "Cache is not available, impossible to delete cache: "+ $!.inspect + end + end + + end + + end + end +end diff --git a/ubiquo_design/lib/ubiquo_design/render_page.rb b/ubiquo_design/lib/ubiquo_design/render_page.rb index 6d77c34e..3c5e6344 100644 --- a/ubiquo_design/lib/ubiquo_design/render_page.rb +++ b/ubiquo_design/lib/ubiquo_design/render_page.rb @@ -22,21 +22,12 @@ def render_page(page) def render_block(block, cached_widgets = {}) uhook_collect_widgets(block) do |widget| next unless widget.valid? - if esi_widget?(widget) - new_params = request.query_parameters.merge('widget' => widget.id) - "" - else - (cached_widgets[widget.id] || render_widget(widget)).tap do |output| - # A widget didn't return an string, return inmediately - return unless output - end + (cached_widgets[widget.id] || render_widget(widget)).tap do |output| + # A widget didn't return an string, return inmediately + return unless output end end end - - def esi_widget?(widget) - Rails.env.production? - end def template_directory Rails.env.test? ? File.join(ActiveSupport::TestCase.fixture_path, "templates") :