105 lines
2.9 KiB
Ruby
105 lines
2.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'set'
|
|
|
|
module Gitlab
|
|
module Pages
|
|
class CacheControl
|
|
include Gitlab::Utils::StrongMemoize
|
|
|
|
EXPIRE = 12.hours
|
|
# To avoid delivering expired deployment URL in the cached payload,
|
|
# use a longer expiration time in the deployment URL
|
|
DEPLOYMENT_EXPIRATION = (EXPIRE + 12.hours)
|
|
|
|
SETTINGS_CACHE_KEY = 'pages_domain_for_%{type}_%{id}'
|
|
PAYLOAD_CACHE_KEY = '%{settings_cache_key}_%{settings_hash}'
|
|
|
|
class << self
|
|
def for_domain(domain_id)
|
|
new(type: :domain, id: domain_id)
|
|
end
|
|
|
|
def for_namespace(namespace_id)
|
|
new(type: :namespace, id: namespace_id)
|
|
end
|
|
end
|
|
|
|
def initialize(type:, id:)
|
|
raise(ArgumentError, "type must be :namespace or :domain") unless %i[namespace domain].include?(type)
|
|
|
|
@type = type
|
|
@id = id
|
|
end
|
|
|
|
def cache_key
|
|
strong_memoize(:payload_cache_key) do
|
|
cache_settings_hash!
|
|
|
|
payload_cache_key_for(settings_hash)
|
|
end
|
|
end
|
|
|
|
# Invalidates the cache.
|
|
#
|
|
# Since rails nodes and sidekiq nodes have different application settings,
|
|
# and the invalidation happens in a sidekiq node, we have to use the
|
|
# cached settings hash to build the payload cache key to be invalidated.
|
|
def clear_cache
|
|
keys = cached_settings_hashes
|
|
.map { |hash| payload_cache_key_for(hash) }
|
|
.push(settings_cache_key)
|
|
|
|
::Gitlab::AppLogger.info(
|
|
message: 'clear pages cache',
|
|
pages_keys: keys,
|
|
pages_type: @type,
|
|
pages_id: @id
|
|
)
|
|
|
|
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
|
Rails.cache.delete_multi(keys)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
# Since rails nodes and sidekiq nodes have different application settings,
|
|
# we cache the application settings hash when creating the payload cache
|
|
# so we can use these values to invalidate the cache in a sidekiq node later.
|
|
def cache_settings_hash!
|
|
cached = cached_settings_hashes.to_set
|
|
Rails.cache.write(settings_cache_key, cached.add(settings_hash))
|
|
end
|
|
|
|
def cached_settings_hashes
|
|
Rails.cache.read(settings_cache_key) || []
|
|
end
|
|
|
|
def payload_cache_key_for(settings_hash)
|
|
PAYLOAD_CACHE_KEY % {
|
|
settings_cache_key: settings_cache_key,
|
|
settings_hash: settings_hash
|
|
}
|
|
end
|
|
|
|
def settings_cache_key
|
|
strong_memoize(:settings_cache_key) do
|
|
SETTINGS_CACHE_KEY % { type: @type, id: @id }
|
|
end
|
|
end
|
|
|
|
def settings_hash
|
|
strong_memoize(:settings_hash) do
|
|
values = ::Gitlab.config.pages.dup
|
|
|
|
values['app_settings'] = ::Gitlab::CurrentSettings.attributes.slice(
|
|
'force_pages_access_control'
|
|
)
|
|
|
|
::Digest::SHA256.hexdigest(values.inspect)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|