about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2020-11-19 17:38:06 +0100
committerGitHub <noreply@github.com>2020-11-19 17:38:06 +0100
commitdf1653174be233f2737d8ec281325dee54011947 (patch)
tree90d2a8fe113cfa3a1184001a94a2bed7b56a6f27
parent1242e57c270e9ff356e8c175670d5dc3a10ad273 (diff)
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.
-rw-r--r--app/lib/cache_buster.rb28
-rw-r--r--app/services/suspend_account_service.rb2
-rw-r--r--app/services/unsuspend_account_service.rb2
-rw-r--r--app/workers/cache_buster_worker.rb18
-rw-r--r--config/initializers/cache_buster.rb10
-rw-r--r--config/initializers/paperclip.rb1
6 files changed, 60 insertions, 1 deletions
diff --git a/app/lib/cache_buster.rb b/app/lib/cache_buster.rb
new file mode 100644
index 000000000..035611518
--- /dev/null
+++ b/app/lib/cache_buster.rb
@@ -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
diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb
index 7c70a6021..19d65280d 100644
--- a/app/services/suspend_account_service.rb
+++ b/app/services/suspend_account_service.rb
@@ -78,6 +78,8 @@ class SuspendAccountService < BaseService
               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
diff --git a/app/services/unsuspend_account_service.rb b/app/services/unsuspend_account_service.rb
index a81d1ac4f..f07a3f053 100644
--- a/app/services/unsuspend_account_service.rb
+++ b/app/services/unsuspend_account_service.rb
@@ -69,6 +69,8 @@ class UnsuspendAccountService < BaseService
               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
diff --git a/app/workers/cache_buster_worker.rb b/app/workers/cache_buster_worker.rb
new file mode 100644
index 000000000..5ad0a44cb
--- /dev/null
+++ b/app/workers/cache_buster_worker.rb
@@ -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
diff --git a/config/initializers/cache_buster.rb b/config/initializers/cache_buster.rb
new file mode 100644
index 000000000..227e450f3
--- /dev/null
+++ b/config/initializers/cache_buster.rb
@@ -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
diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb
index b841d5220..25adcd8d6 100644
--- a/config/initializers/paperclip.rb
+++ b/config/initializers/paperclip.rb
@@ -107,7 +107,6 @@ elsif ENV['SWIFT_ENABLED'] == 'true'
 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',
   )