Add cache buster feature for media files (#15155)

Nginx can be configured to bypass proxy cache when a special header
is in the request. If the response is cacheable, it will replace
the cache for that request. Proxy caching of media files is
desirable when using object storage as a way of minimizing bandwidth
costs, but has the drawback of leaving deleted media files for
a configured amount of cache time. A cache buster can make those
media files immediately unavailable. This especially makes sense
when suspending and unsuspending an account.
This commit is contained in:
Eugen Rochko 2020-11-19 17:38:06 +01:00 committed by GitHub
parent 1242e57c27
commit df1653174b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 1 deletions

28
app/lib/cache_buster.rb Normal file
View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
class CacheBuster
def initialize(options = {})
@secret_header = options[:secret_header] || 'Secret-Header'
@secret = options[:secret] || 'True'
end
def bust(url)
site = Addressable::URI.parse(url).normalized_site
request_pool.with(site) do |http_client|
build_request(url, http_client).perform
end
end
private
def request_pool
RequestPool.current
end
def build_request(url, http_client)
Request.new(:get, url, http_client: http_client).tap do |request|
request.add_headers(@secret_header => @secret)
end
end
end

View file

@ -78,6 +78,8 @@ class SuspendAccountService < BaseService
Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}" Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}"
end end
end end
CacheBusterWorker.perform_async(attachment.path(style)) if Rails.configuration.x.cache_buster_enabled
end end
end end
end end

View file

@ -69,6 +69,8 @@ class UnsuspendAccountService < BaseService
Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}" Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}"
end end
end end
CacheBusterWorker.perform_async(attachment.path(style)) if Rails.configuration.x.cache_buster_enabled
end end
end end
end end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
class CacheBusterWorker
include Sidekiq::Worker
include RoutingHelper
sidekiq_options queue: 'pull'
def perform(path)
cache_buster.bust(full_asset_url(path))
end
private
def cache_buster
CacheBuster.new(Rails.configuration.x.cache_buster)
end
end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.cache_buster_enabled = ENV['CACHE_BUSTER_ENABLED'] == 'true'
config.x.cache_buster = {
secret_header: ENV['CACHE_BUSTER_SECRET_HEADER'],
secret: ENV['CACHE_BUSTER_SECRET'],
}
end

View file

@ -107,7 +107,6 @@ elsif ENV['SWIFT_ENABLED'] == 'true'
else else
Paperclip::Attachment.default_options.merge!( Paperclip::Attachment.default_options.merge!(
storage: :filesystem, storage: :filesystem,
use_timestamp: true,
path: File.join(ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system')), ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'), path: File.join(ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system')), ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'),
url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename', url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename',
) )