Allow Nginx cached static content to be purged (#9857) [deploy]
* Only bust_fastly_cache if fastly is enabled * Conditionally bust nginx cache from CacheBuster#bust * Don't _actually_ call out to openresty * Remove redundant check for FASTLY_API_KEY in CacheBuster * Clean up and add a spec * Do not call .purge_ methods if fastly is not configured * Add OPENRESTY_ ENV vars to .env_sample * Remove extra / prepending path * Remove ConfigurationError, clean up Purgeable concern * Use raise instead of fail like fastly-ruby * No longer check for Rails.env.production? * Use let! to create article in BustMultipleCachesWorker spec
This commit is contained in:
parent
07adb7eab9
commit
9e40e68682
8 changed files with 93 additions and 17 deletions
|
|
@ -2,6 +2,10 @@
|
|||
export APP_DOMAIN="localhost:3000"
|
||||
export APP_PROTOCOL="http://"
|
||||
|
||||
# Openresty domain + Protocol setting for development
|
||||
export OPENRESTY_DOMAIN=""
|
||||
export OPENRESTY_PROTOCOL=""
|
||||
|
||||
# Community Related Variables
|
||||
export COMMUNITY_NAME="DEV(local)"
|
||||
|
||||
|
|
|
|||
|
|
@ -18,18 +18,49 @@ module CacheBuster
|
|||
# fastly.purge(path)
|
||||
#
|
||||
# https://github.com/fastly/fastly-ruby#efficient-purging
|
||||
return unless Rails.env.production?
|
||||
return if ApplicationConfig["FASTLY_API_KEY"].blank?
|
||||
|
||||
HTTParty.post("https://api.fastly.com/purge/https://#{ApplicationConfig['APP_DOMAIN']}#{path}",
|
||||
headers: { "Fastly-Key" => ApplicationConfig["FASTLY_API_KEY"] })
|
||||
HTTParty.post("https://api.fastly.com/purge/https://#{ApplicationConfig['APP_DOMAIN']}#{path}?i=i",
|
||||
headers: { "Fastly-Key" => ApplicationConfig["FASTLY_API_KEY"] })
|
||||
if fastly_enabled?
|
||||
bust_fastly_cache(path)
|
||||
elsif nginx_enabled?
|
||||
bust_nginx_cache(path)
|
||||
end
|
||||
rescue URI::InvalidURIError => e
|
||||
Rails.logger.error("Trying to bust cache of an invalid uri: #{e}")
|
||||
DatadogStatsClient.increment("cache_buster.invalid_uri", tags: ["path:#{path}"])
|
||||
end
|
||||
|
||||
def self.fastly_enabled?
|
||||
ApplicationConfig["FASTLY_API_KEY"].present? && ApplicationConfig["FASTLY_SERVICE_ID"].present?
|
||||
end
|
||||
|
||||
def self.nginx_enabled?
|
||||
ApplicationConfig["OPENRESTY_PROTOCOL"].present? && ApplicationConfig["OPENRESTY_DOMAIN"].present?
|
||||
end
|
||||
|
||||
def self.bust_fastly_cache(path)
|
||||
HTTParty.post(
|
||||
"https://api.fastly.com/purge/https://#{ApplicationConfig['APP_DOMAIN']}#{path}",
|
||||
headers: {
|
||||
"Fastly-Key" => ApplicationConfig["FASTLY_API_KEY"]
|
||||
},
|
||||
)
|
||||
HTTParty.post(
|
||||
"https://api.fastly.com/purge/https://#{ApplicationConfig['APP_DOMAIN']}#{path}?i=i",
|
||||
headers: {
|
||||
"Fastly-Key" => ApplicationConfig["FASTLY_API_KEY"]
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
def self.bust_nginx_cache(path)
|
||||
uri = URI.parse("#{ApplicationConfig['OPENRESTY_PROTOCOL']}#{ApplicationConfig['OPENRESTY_DOMAIN']}#{path}")
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
response = http.request Net::HTTP::NginxPurge.new(uri.request_uri)
|
||||
|
||||
raise StandardError, "NginxPurge request failed: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
|
||||
|
||||
response.body
|
||||
end
|
||||
|
||||
def self.bust_comment(commentable)
|
||||
return unless commentable
|
||||
|
||||
|
|
@ -206,3 +237,12 @@ module CacheBuster
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Creates our own purge method for an HTTP request,
|
||||
# which is used by Nginx to bust a cache.
|
||||
# See Net::HTTPGenericRequest for attributes/methods.
|
||||
class Net::HTTP::NginxPurge < Net::HTTPRequest # rubocop:disable Style/ClassAndModuleChildren
|
||||
METHOD = "PURGE".freeze
|
||||
REQUEST_HAS_BODY = false
|
||||
RESPONSE_HAS_BODY = true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -645,8 +645,6 @@ class Article < ApplicationRecord
|
|||
end
|
||||
|
||||
def bust_cache
|
||||
return unless Rails.env.production?
|
||||
|
||||
CacheBuster.bust(path)
|
||||
CacheBuster.bust("#{path}?i=i")
|
||||
CacheBuster.bust("#{path}?preview=#{password}")
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
# Copied from the deprecated fastly-rails gem
|
||||
# https://github.com/fastly/fastly-rails/blob/master/lib/fastly-rails/active_record/surrogate_key.rb
|
||||
#
|
||||
# This concern handles purge and purge_all calls to purge the edge cache (Fastly)
|
||||
# This concern handles purge and purge_all calls to purge Fastly's edge cache.
|
||||
# If Fastly has not been configured, these methods will short circuit and not be invoked.
|
||||
module Purgeable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
def purge_all
|
||||
return if Rails.env.development?
|
||||
return unless fastly
|
||||
|
||||
service.purge_by_key(table_key)
|
||||
end
|
||||
|
||||
def soft_purge_all
|
||||
return if Rails.env.development?
|
||||
return unless fastly
|
||||
|
||||
service.purge_by_key(table_key, true)
|
||||
end
|
||||
|
|
@ -23,13 +24,14 @@ module Purgeable
|
|||
end
|
||||
|
||||
def fastly
|
||||
return if Rails.env.development?
|
||||
return false if Rails.env.development?
|
||||
return false if ApplicationConfig["FASTLY_API_KEY"].blank? || ApplicationConfig["FASTLY_SERVICE_ID"].blank?
|
||||
|
||||
Fastly.new(api_key: ApplicationConfig["FASTLY_API_KEY"])
|
||||
end
|
||||
|
||||
def service
|
||||
return if Rails.env.development?
|
||||
return unless fastly
|
||||
|
||||
Fastly::Service.new({ id: ApplicationConfig["FASTLY_SERVICE_ID"] }, fastly)
|
||||
end
|
||||
|
|
@ -45,13 +47,13 @@ module Purgeable
|
|||
end
|
||||
|
||||
def purge
|
||||
return if Rails.env.development?
|
||||
return unless fastly
|
||||
|
||||
service.purge_by_key(record_key)
|
||||
end
|
||||
|
||||
def soft_purge
|
||||
return if Rails.env.development?
|
||||
return unless fastly
|
||||
|
||||
service.purge_by_key(record_key, true)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,6 +11,31 @@ RSpec.describe CacheBuster, type: :labor do
|
|||
let(:podcast_episode) { create(:podcast_episode, podcast_id: podcast.id) }
|
||||
let(:tag) { create(:tag) }
|
||||
|
||||
describe "#bust_nginx_cache" do
|
||||
before do
|
||||
allow(cache_buster).to receive(:bust_nginx_cache).and_call_original
|
||||
allow(ApplicationConfig).to receive(:[]).with("OPENRESTY_PROTOCOL").and_return("http://")
|
||||
allow(ApplicationConfig).to receive(:[]).with("OPENRESTY_DOMAIN").and_return("localhost:9090")
|
||||
end
|
||||
|
||||
it "can bust an nginx cache when configured" do
|
||||
cache_buster.bust_nginx_cache("/#{user.username}")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#bust_fastly_cache" do
|
||||
before do
|
||||
allow(cache_buster).to receive(:bust_fastly_cache).and_call_original
|
||||
allow(ApplicationConfig).to receive(:[]).with("APP_DOMAIN").and_return("fake-key")
|
||||
allow(ApplicationConfig).to receive(:[]).with("FASTLY_API_KEY").and_return("fake-key")
|
||||
allow(ApplicationConfig).to receive(:[]).with("FASTLY_SERVICE_ID").and_return("localhost:3000")
|
||||
end
|
||||
|
||||
it "can bust a fastly cache when configured" do
|
||||
cache_buster.bust_fastly_cache("/#{user.username}")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#bust_comment" do
|
||||
it "busts comment" do
|
||||
cache_buster.bust_comment(comment.commentable)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ RSpec.describe Purgeable do
|
|||
let(:fastly_service) { instance_double(Fastly::Service) }
|
||||
|
||||
before do
|
||||
allow(ApplicationConfig).to receive(:[]).with("FASTLY_API_KEY").and_return("fake-key")
|
||||
allow(ApplicationConfig).to receive(:[]).with("FASTLY_SERVICE_ID").and_return("fake-service-id")
|
||||
allow(Fastly::Service).to receive(:new).and_return(fastly_service)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,9 @@ RSpec.configure do |config|
|
|||
stub_request(:post, /api.fastly.com/)
|
||||
.to_return(status: 200, body: "".to_json, headers: {})
|
||||
|
||||
stub_request(:any, /localhost:9090/)
|
||||
.to_return(status: 200, body: "OK".to_json, headers: {})
|
||||
|
||||
stub_request(:post, /api.bufferapp.com/)
|
||||
.to_return(status: 200, body: { fake_text: "so fake" }.to_json, headers: {})
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ require "rails_helper"
|
|||
|
||||
RSpec.describe Articles::BustMultipleCachesWorker, type: :worker do
|
||||
describe "#perform" do
|
||||
let(:article) { create(:article) }
|
||||
# Explicitly create article before the test is invoked, since
|
||||
# creating an article will invoke CacheBuster#bust in a callback.
|
||||
let!(:article) { create(:article) }
|
||||
let(:path) { article.path }
|
||||
let(:worker) { subject }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue