From a9bf43c1fd2f45ed8d10d3f211a2ac72feb8d730 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 9 Dec 2012 19:22:33 +0100 Subject: [PATCH] always use etag for caching when cache_key or updated_at are present, add the deploy_sha as a cache buster --- lib/travis/api/app.rb | 11 ++- lib/travis/api/app/responders/service.rb | 104 +++++++++++++---------- 2 files changed, 66 insertions(+), 49 deletions(-) diff --git a/lib/travis/api/app.rb b/lib/travis/api/app.rb index 582f4ac8..bedd863f 100644 --- a/lib/travis/api/app.rb +++ b/lib/travis/api/app.rb @@ -51,6 +51,10 @@ module Travis::Api super() end + def self.deploy_sha + @deploy_sha ||= File.exist?('.deploy_sha') ? File.read('.deploy-sha')[0..7] : 'deploy-sha' + end + attr_accessor :app def initialize @@ -64,11 +68,10 @@ module Travis::Api memcache_servers = ENV['MEMCACHE_SERVERS'] if Travis::Features.feature_active?(:use_rack_cache) && memcache_server - namespace = File.read('.deploy-sha')[0..7] use Rack::Cache, verbose: true, - metastore: "memcached://#{memcache_servers}/#{namespace}", - entitystore: "memcached://#{memcache_servers}/#{namespace}" + metastore: "memcached://#{memcache_servers}/#{self.class.deploy_sha}", + entitystore: "memcached://#{memcache_servers}/#{self.class.deploy_sha}" end use Rack::Deflater @@ -115,7 +118,7 @@ module Travis::Api Raven.configure do |config| config.dsn = Travis.config.sentry.dsn end if Travis.config.sentry - + Travis::LogSubscriber::ActiveRecordMetrics.attach $metriks_reporter = Metriks::Reporter::Logger.new end diff --git a/lib/travis/api/app/responders/service.rb b/lib/travis/api/app/responders/service.rb index bc775195..55316b27 100644 --- a/lib/travis/api/app/responders/service.rb +++ b/lib/travis/api/app/responders/service.rb @@ -1,54 +1,68 @@ -module Travis::Api::App::Responders - class Service < Base - def apply? - resource.respond_to?(:run) - end +require 'digest/md5' - def apply - cache_control - result = normalize(resource.run) - result[:flash] = resource.messages if result && resource.respond_to?(:messages) # TODO should rather happen in the JSON responder, no? - result - end +module Travis::Api + class App + module Responders + class Service < Base + include Helpers::Accept - private - - def cache_control - if final? - mode = endpoint.public? ? :public : :private - endpoint.expires(31536000, mode) # 1 year - else - # FIXME: Chrome WTF? - endpoint.cache_control :no_cache + def apply? + resource.respond_to?(:run) end - endpoint.etag resource.cache_key if cache_key? - endpoint.last_modified resource.updated_at if updated_at? - end - - def final? - resource.respond_to?(:final?) && resource.final? - end - - def updated_at? - resource.respond_to?(:updated_at) && resource.updated_at - end - - def cache_key? - resource.respond_to?(:cache_key) && resource.cache_key - end - - # Services potentially return all sorts of things - # If it's a string, true or false we'll wrap it into a hash. - # If it's an active record or scope we just pass so it can be processed by the json responder. - # If it's nil we also pass it but yield not_found. - def normalize(result) - case result - when String, true, false - { result: result } - else + def apply + cache_control + result = normalize(resource.run) + result[:flash] = resource.messages if result && resource.respond_to?(:messages) # TODO should rather happen in the JSON responder, no? result end + + private + + def cache_control + if final? + mode = endpoint.public? ? :public : :private + endpoint.expires(31536000, mode) # 1 year + else + # FIXME: Chrome WTF? + endpoint.cache_control :no_cache + end + + endpoint.etag cache_key if cache_key + end + + def final? + resource.respond_to?(:final?) && resource.final? + end + + def cache_key + cache_key ||= begin + key = resource_cache_key || resource_updated_at + Digest::MD5.hexdigest([App.deploy_sha, key].join('-')) if key + end + end + + def resource_cache_key + resource.respond_to?(:updated_at) && resource.updated_at + end + + def resource_updated_at + resource.respond_to?(:updated_at) && resource.updated_at.try(:strftime, '%FT%T%:z') + end + + # Services potentially return all sorts of things + # If it's a string, true or false we'll wrap it into a hash. + # If it's an active record or scope we just pass so it can be processed by the json responder. + # If it's nil we also pass it but yield not_found. + def normalize(result) + case result + when String, true, false + { result: result } + else + result + end + end end + end end end