Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

Commit

Permalink
Add cache buster feature for media files (mastodon#15155)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Gargron authored Nov 19, 2020
1 parent 1242e57 commit df16531
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 1 deletion.
28 changes: 28 additions & 0 deletions app/lib/cache_buster.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions app/services/suspend_account_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ def privatize_media_attachments!
Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}"
end
end

CacheBusterWorker.perform_async(attachment.path(style)) if Rails.configuration.x.cache_buster_enabled
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions app/services/unsuspend_account_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ def publish_media_attachments!
Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}"
end
end

CacheBusterWorker.perform_async(attachment.path(style)) if Rails.configuration.x.cache_buster_enabled
end
end
end
Expand Down
18 changes: 18 additions & 0 deletions app/workers/cache_buster_worker.rb
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions config/initializers/cache_buster.rb
Original file line number Diff line number Diff line change
@@ -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
1 change: 0 additions & 1 deletion config/initializers/paperclip.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
else
Paperclip::Attachment.default_options.merge!(
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'),
url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename',
)
Expand Down

0 comments on commit df16531

Please sign in to comment.