Spec-Zone.ru › Ruby on Rails 7.2

класс ActiveSupport::Cache::Store

Родитель:
Объект

Хранилище кэша Active Support

Абстрактный класс хранилища кэша. Существуют различные реализации хранилищ кэша, каждая со своими дополнительными функциями. См. классы в модуле ActiveSupport::Cache, например, ActiveSupport::Cache::MemCacheStore. MemCacheStore в настоящее время является наиболее популярным хранилищем кэша для крупных веб-сайтов в производстве.

Некоторые реализации могут не поддерживать все методы за пределами основных методов кэша fetch, write, read, exist? и delete.

ActiveSupport::Cache::Store может хранить любые объекты Ruby, которые поддерживаются методами coder и dump.

cache = ActiveSupport::Cache::MemoryStore.new

cache.read('city')   # => nil
cache.write('city', "Duckburgh") # => true
cache.read('city')   # => "Duckburgh"

cache.write('not serializable', Proc.new {}) # => TypeError

Ключи всегда преобразуются в строки и чувствительны к регистру. Когда объект задается как ключ и имеет определённый метод cache_key, этот метод будет вызван для определения ключа. В противном случае будет вызван метод to_param. Массивы и хэши также могут использоваться в качестве ключей. Элементы будут разделены слэшами, а элементы внутри Hash будут отсортированы по ключу для обеспечения согласованности.

cache.read('city') == cache.read(:city)   # => true

Значения Nil могут быть помещены в кэш.

Если ваш кэш находится на общей инфраструктуре, вы можете определить пространство имен для ваших записей в кэше. Если пространство имен определено, оно будет добавляться в префикс к каждому ключу. Пространство имен может быть либо статическим значением, либо функцией. Если это функция, она будет вызвана при оценке каждого ключа, так что вы сможете использовать логику приложения для обновления ключей.

cache.namespace = -> { @last_mod_time }  # Set the namespace to a variable
@last_mod_time = Time.now  # Invalidate the entire cache by changing namespace

Атрибуты

options[R]
silence[R]
silence?[R]

Публичные методы класса

new(options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 295
def initialize(options = nil)
  @options = options ? validate_options(normalize_options(options)) : {}

  @options[:compress] = true unless @options.key?(:compress)
  @options[:compress_threshold] ||= DEFAULT_COMPRESS_LIMIT

  @coder = @options.delete(:coder) do
    legacy_serializer = Cache.format_version < 7.1 && !@options[:serializer]
    serializer = @options.delete(:serializer) || default_serializer
    serializer = Cache::SerializerWithFallback[serializer] if serializer.is_a?(Symbol)
    compressor = @options.delete(:compressor) { Zlib }

    Cache::Coder.new(serializer, compressor, legacy_serializer: legacy_serializer)
  end

  @coder ||= Cache::SerializerWithFallback[:passthrough]

  @coder_supports_compression = @coder.respond_to?(:dump_compressed)
end

Создает новый кэш.

Параметры

:namespace

Устанавливает пространство имен для кэша. Этот параметр особенно полезен, если ваше приложение использует кэш совместно с другими приложениями.

:serializer

Сериализатор для значений кэша. Должен отвечать на dump и load.

По умолчанию сериализатор зависит от версии формата кэша (установленного через config.active_support.cache_format_version при использовании Rails). Сериализатор по умолчанию для каждой версии формата включает механизм обратной совместимости для десериализации значений из любой версии формата. Это поведение упрощает миграцию между версиями формата без сброса всего кэша.

Вы также можете указать serializer: :message_pack для использования предварительно настроенного сериализатора на основе ActiveSupport::MessagePack. Сериализатор :message_pack включает тот же механизм обратной совместимости при десериализации, что облегчает миграцию из (или в) стандартного сериализатора. Сериализатор :message_pack может повысить производительность, но требует использования msgpack gem.

:compressor

Компрессор для сериализованных значений кэша. Должен отвечать на deflate и inflate.

По умолчанию используется компрессор Zlib. Чтобы определить новый пользовательский компрессор, который также распаковывает старые записи кэша, вы можете проверить сжатые значения на наличие подписи Zlib "\x78".

module MyCompressor
  def self.deflate(dumped)
    # compression logic... (make sure result does not start with "\x78"!)
  end

  def self.inflate(compressed)
    if compressed.start_with?("\x78")
      Zlib.inflate(compressed)
    else
      # decompression logic...
    end
  end
end

ActiveSupport::Cache.lookup_store(:redis_cache_store, compressor: MyCompressor)
:coder

Кодер для сериализации и (необязательно) сжатия записей кэша. Должен отвечать на dump и load.

По умолчанию кодер комбинирует сериализатор и компрессор и включает некоторые оптимизации производительности. Если вам нужно только переопределить сериализатор или компрессор, вы должны указать параметры :serializer или :compressor соответственно.

Если хранилище может обрабатывать записи кэша напрямую, вы также можете указать coder: nil для исключения сериализатора, компрессора и кодера. Например, если вы используете ActiveSupport::Cache::MemoryStore и можете гарантировать, что значения кэша не изменятся, вы можете указать coder: nil для избежания накладных расходов по защите от изменений.

Параметр :coder взаимоисключающий с параметрами :serializer и :compressor . Их совместное использование вызовет ArgumentError.

Любые другие указанные параметры обрабатываются как параметры по умолчанию для соответствующих операций кэширования, таких как read, write и fetch.

Общедоступные методы экземпляра

cleanup(options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 747
def cleanup(options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support cleanup")
end

Очищает кэш, удаляя устаревшие записи.

Параметры передаются в базовую реализацию кэша.

Некоторые реализации могут не поддерживать этот метод.

clear(options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 757
def clear(options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support clear")
end

Очищает весь кэш. Будьте осторожны с этим методом, так как он может повлиять на другие процессы, если используется общий кэш.

Хэш параметров передаётся базовой реализации кэша.

Некоторые реализации могут не поддерживать этот метод.

decrement(name, amount = 1, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 738
def decrement(name, amount = 1, options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
end

Уменьшает целочисленное значение в кэше.

Параметры передаются в базовую реализацию кэша.

Некоторые реализации могут не поддерживать этот метод.

delete(name, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 674
def delete(name, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:delete, key) do
    delete_entry(key, **options)
  end
end

Удаляет запись в кэше. Возвращает true, если запись удалена, и false, в противном случае.

Параметры передаются в базовую реализацию кэша.

delete_matched(matcher, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 720
def delete_matched(matcher, options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
end

Удаляет все записи с ключами, соответствующими шаблону.

Параметры передаются в базовую реализацию кэша.

Некоторые реализации могут не поддерживать этот метод.

delete_multi(names, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 687
def delete_multi(names, options = nil)
  return 0 if names.empty?

  options = merged_options(options)
  names.map! { |key| normalize_key(key, options) }

  instrument_multi :delete_multi, names do
    delete_multi_entries(names, **options)
  end
end

Удаляет несколько записей в кэше. Возвращает количество удалённых записей.

Параметры передаются в базовую реализацию кэша.

exist?(name, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 701
def exist?(name, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:exist?, key) do |payload|
    entry = read_entry(key, **options, event: payload)
    (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
  end
end

Возвращает true, если кэш содержит запись для данного ключа.

Параметры передаются в базовую реализацию кэша.

fetch(name, options = nil, &block) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 444
def fetch(name, options = nil, &block)
  if block_given?
    options = merged_options(options)
    key = normalize_key(name, options)

    entry = nil
    unless options[:force]
      instrument(:read, key, options) do |payload|
        cached_entry = read_entry(key, **options, event: payload)
        entry = handle_expired_entry(cached_entry, key, options)
        if entry
          if entry.mismatched?(normalize_version(name, options))
            entry = nil
          else
            begin
              entry.value
            rescue DeserializationError
              entry = nil
            end
          end
        end
        payload[:super_operation] = :fetch if payload
        payload[:hit] = !!entry if payload
      end
    end

    if entry
      get_entry_value(entry, name, options)
    else
      save_block_result_to_cache(name, key, options, &block)
    end
  elsif options && options[:force]
    raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
  else
    read(name, options)
  end
end

Извлекает данные из кэша по заданному ключу. Если в кэше есть данные с данным ключом, то возвращаются эти данные.

Если таких данных в кэше нет (промах кэша), то возвращается nil. Однако, если передан блок, этот блок передаст ключ и выполнится в случае промаха кэша. Результат работы блока запишется в кэш под заданным ключом, и этот результат будет возвращён.

cache.write('today', 'Monday')
cache.fetch('today')  # => "Monday"

cache.fetch('city')   # => nil
cache.fetch('city') do
  'Duckburgh'
end
cache.fetch('city')   # => "Duckburgh"

Параметры

Внутренне, fetch вызывает read_entry, а при промахе кэша вызывает write_entry. Таким образом, fetch поддерживает те же параметры, что и read и write. Кроме того, fetch поддерживает следующие параметры:

  • force: true — принудительно вызывает «промах» кэша, что означает, что мы рассматриваем значение кэша как пропущенное, даже если оно присутствует. Передача блока обязательна, когда force равно true, так что это всегда приводит к записи в кэш.

    cache.write('today', 'Monday')
    cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
    cache.fetch('today', force: true) # => ArgumentError
    

    Параметр :force полезен, когда вы вызываете какой-либо другой метод, чтобы спросить, нужно ли принудительно записывать в кэш. В противном случае, яснее просто вызвать write.

  • skip_nil: true — предотвращает сохранение нулевого результата в кэше:

    cache.fetch('foo') { nil }
    cache.fetch('bar', skip_nil: true) { nil }
    cache.exist?('foo') # => true
    cache.exist?('bar') # => false
    
  • :race_condition_ttl — задаёт количество секунд, в течение которых устаревшее значение может быть повторно использовано, пока генерируется новое значение. Это может быть использовано для предотвращения гонки при истечении срока действия записей кэша, предотвращая одновременное перегенерирование одной и той же записи несколькими процессами (также известный как эффект «кучи собак»).

    Когда процесс сталкивается со значением в кэше, срок действия которого истек менее чем :race_condition_ttl секунд назад, он продлит срок действия на :race_condition_ttl секунд перед генерированием нового значения. В течение этого расширенного временного окна, в то время как процесс генерирует новое значение, другие процессы будут продолжать использовать старое значение. После того, как первый процесс запишет новое значение, другие процессы будут использовать его.

    Если первый процесс ошибается при генерировании нового значения, другой процесс может попытаться сгенерировать новое значение после истечения расширенного временного окна.

    # Set all values to expire after one minute.
    cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
    
    cache.write("foo", "original value")
    val_1 = nil
    val_2 = nil
    p cache.read("foo") # => "original value"
    
    sleep 1 # wait until the cache expires
    
    t1 = Thread.new do
      # fetch does the following:
      # 1. gets an recent expired entry
      # 2. extends the expiry by 2 seconds (race_condition_ttl)
      # 3. regenerates the new value
      val_1 = cache.fetch("foo", race_condition_ttl: 2) do
        sleep 1
        "new value 1"
      end
    end
    
    # Wait until t1 extends the expiry of the entry
    # but before generating the new value
    sleep 0.1
    
    val_2 = cache.fetch("foo", race_condition_ttl: 2) do
      # This block won't be executed because t1 extended the expiry
      "new value 2"
    end
    
    t1.join
    
    p val_1 # => "new value 1"
    p val_2 # => "oritinal value"
    p cache.fetch("foo") # => "new value 1"
    
    # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
    # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1
    # more second to see the entry expire.
    sleep 1
    
    p cache.fetch("foo") # => nil
    

Динамические параметры

В некоторых случаях может потребоваться динамически вычислять параметры на основе значения в кэше. Для поддержки этого экземпляр ActiveSupport::Cache::WriteOptions передаётся как второй аргумент в блок. Например:

cache.fetch("authentication-token:#{user.id}") do |key, options|
  token = authenticate_to_service
  options.expires_at = token.expires_at
  token
end
fetch_multi(*names) { |name| ... } Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 593
def fetch_multi(*names)
  raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
  return {} if names.empty?

  options = names.extract_options!
  options = merged_options(options)

  writes  = {}
  ordered = instrument_multi :read_multi, names, options do |payload|
    if options[:force]
      reads = {}
    else
      reads = read_multi_entries(names, **options)
    end

    ordered = names.index_with do |name|
      reads.fetch(name) { writes[name] = yield(name) }
    end
    writes.compact! if options[:skip_nil]

    payload[:hits] = reads.keys
    payload[:super_operation] = :fetch_multi

    ordered
  end

  write_multi(writes, options)

  ordered
end

Извлекает данные из кэша по заданным ключам. Если в кэше есть данные с заданными ключами, то возвращаются эти данные. В противном случае, для каждого ключа, для которого не было данных, вызывается переданный блок, и результат будет записан в кэш и возвращён. Таким образом, вам нужно передать блок, возвращающий данные для записи в кэш. Если вы не хотите записывать в кэш при отсутствии данных, используйте read_multi.

Возвращает хеш с данными для каждого из имен. Например:

cache.write("bim", "bam")
cache.fetch_multi("bim", "unknown_key") do |key|
  "Fallback value for key: #{key}"
end
# => { "bim" => "bam",
#      "unknown_key" => "Fallback value for key: unknown_key" }

Вы также можете указать дополнительные параметры через аргумент options. Смотрите fetch для получения подробной информации. Другие параметры передаются базовой реализации кэша. Например:

cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
  "buzz"
end
# => {"fizz"=>"buzz"}
cache.read("fizz")
# => "buzz"
sleep(6)
cache.read("fizz")
# => nil
increment(name, amount = 1, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 729
def increment(name, amount = 1, options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support increment")
end

Увеличивает целочисленное значение в кэше.

Параметры передаются в базовую реализацию кэша.

Некоторые реализации могут не поддерживать этот метод.

mute() { || ... } Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 322
def mute
  previous_silence, @silence = @silence, true
  yield
ensure
  @silence = previous_silence
end

Отключает логирование внутри блока.

read(name, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 498
def read(name, options = nil)
  options = merged_options(options)
  key     = normalize_key(name, options)
  version = normalize_version(name, options)

  instrument(:read, key, options) do |payload|
    entry = read_entry(key, **options, event: payload)

    if entry
      if entry.expired?
        delete_entry(key, **options)
        payload[:hit] = false if payload
        nil
      elsif entry.mismatched?(version)
        payload[:hit] = false if payload
        nil
      else
        payload[:hit] = true if payload
        begin
          entry.value
        rescue DeserializationError
          payload[:hit] = false
          nil
        end
      end
    else
      payload[:hit] = false if payload
      nil
    end
  end
end

Читает данные из кэша по заданному ключу. Если в кэше есть данные с этим ключом, то эти данные возвращаются. В противном случае, возвращается nil.

Обратите внимание, что если данные были записаны с параметрами :expires_in или :version, оба эти условия применяются перед возвратом данных.

Параметры

  • :namespace — Замена пространства имён хранилища для этого вызова.

  • :version — Указывает версию записи кэша. Если версия кэшированного значения не совпадает с запрошенной версией, чтение будет обрабатываться как промах кэша. Эта функция используется для поддержки переиспользуемых ключей кэша.

Другие параметры будут обработаны конкретной реализацией хранилища кэша.

read_multi(*names) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 536
def read_multi(*names)
  return {} if names.empty?

  options = names.extract_options!
  options = merged_options(options)

  instrument_multi :read_multi, names, options do |payload|
    read_multi_entries(names, **options, event: payload).tap do |results|
      payload[:hits] = results.keys
    end
  end
end

Читает сразу несколько значений из кэша. Параметры можно передать в последнем аргументе.

Некоторые реализации кэша могут оптимизировать этот метод.

Возвращает хеш, сопоставляющий предоставленные имена с найденными значениями.

silence!() Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 316
def silence!
  @silence = true
  self
end

Отключает регистрирующий механизм.

write(name, value, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 660
def write(name, value, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:write, key, options) do
    entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
    write_entry(key, entry, **options)
  end
end

Записывает значение в кэш по ключу. Значение должно поддерживаться методами coder и dump хранилища load.

Возвращает true при успешном выполнении записи, nil в случае ошибки взаимодействия с кэшем или false в случае неудачи записи по другой причине.

По умолчанию записи в кэш, превышающие 1 КБ, сжимаются. Сжатие позволяет хранить больше данных в том же объёме памяти, что приводит к меньшим вытеснениям из кэша и более высоким показателям попадания.

Параметры

  • compress: false - Отключает сжатие записи в кэш.

  • :compress_threshold - Пороговое значение для сжатия, указанное в байтах. Записи в кэше, превышающие этот порог, будут сжиматься. По умолчанию 1.kilobyte.

  • :expires_in - Устанавливает относительное время истечения срока действия записи в кэше, указанное в секундах. :expire_in и :expired_in являются псевдонимами для :expires_in.

    cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
    cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
    
  • :expires_at - Устанавливает абсолютное время истечения срока действия записи в кэше.

    cache = ActiveSupport::Cache::MemoryStore.new
    cache.write(key, value, expires_at: Time.now.at_end_of_hour)
    
  • :version - Указывает версию записи в кэше. При чтении из кэша, если версия кэшированного значения не соответствует запрошенной, чтение обрабатывается как промах кэша. Эта функция используется для поддержки переиспользуемых ключей кэша.

Другие параметры будут обработаны конкретной реализацией хранилища кэша.

write_multi(hash, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 550
def write_multi(hash, options = nil)
  return hash if hash.empty?

  options = merged_options(options)

  instrument_multi :write_multi, hash, options do |payload|
    entries = hash.each_with_object({}) do |(name, value), memo|
      memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
    end

    write_multi_entries entries, **options
  end
end

Cache API хранения для записи нескольких значений сразу.

Приватные методы экземпляра

key_matcher(pattern, options) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 777
def key_matcher(pattern, options) # :doc:
  prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
  if prefix
    source = pattern.source
    if source.start_with?("^")
      source = source[1, source.length]
    else
      source = ".*#{source[0, source.length]}"
    end
    Regexp.new("^#{Regexp.escape(prefix)}:#{source}", pattern.options)
  else
    pattern
  end
end

Добавляет пространство имён, определённое в параметрах, к шаблону, предназначенному для сопоставления ключей. Реализации, поддерживающие delete_matched, должны вызывать этот метод для преобразования шаблона, сопоставляющего имена, в шаблон, сопоставляющий именованные ключи.

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API