Совместное использование "рабочего" решения
Поскольку ActiveSupport::CachingKeyGenerator
использует Concurrent::Map
, я обнаружил, что ключи кэширования приведут к увеличению использования памяти, пропорциональному количеству пользователей (при условии, что всезапросы как-то направляются на один и тот же узел).
Для решения этой проблемы я написал аналогичный CachingKeyGenerator
, который охватывает ActiveSupport::KeyGenerator
и ActiveSupport::Cache::MemoryStore
.
class CachingKeyGenerator
BASE = Rails.application.secrets.secret_key_base
LENGTH = ActiveSupport::MessageEncryptor.key_len
KEY_EXPIRY = 1.day
def initialize
@key_generator = ActiveSupport::KeyGenerator.new(Rails.application.secrets.secret_key_base)
@keys_cache = ActiveSupport::Cache::MemoryStore.new(expires_in: KEY_EXPIRY)
end
def generate_key(salt)
key = @keys_cache.fetch(salt)
if key.nil?
key = @key_generator.generate_key(salt, LENGTH)
@keys_cache.write(salt, key)
end
key
end
end
Согласно документации Rails, ActiveSupport::Cache::MemoryStore
является поточно-ориентированным и реализует механизм очистки на основе LRU [1].Это должно сделать использование памяти кеша детерминированным - до размера, установленного для хранилища памяти (по умолчанию - 32 МБ, может быть определено во время инициализации).
PS: еще для развертывания этого на производстве, обновлюздесь, если у меня возникнут неожиданные проблемы.
[1] http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemoryStore.html