Кэширование Active Model Serializer 10. Кажется, это не работает. Почему?

В моем игрушечном приложении есть пара моделей, rent_units и пользователи. Вы можете найти репозиторий здесь

Я использую Rails 5 и AMS 10.

active_model_serializers (0.10.0.rc4)
...
rails (5.0.0.beta3)
      actioncable (= 5.0.0.beta3)
      actionmailer (= 5.0.0.beta3)
      actionpack (= 5.0.0.beta3)
...

У меня есть RentalUnitSerializer, который выглядит так:

class RentalUnitSerializer < ActiveModel::Serializer
  cache key: 'rental_unit', expires_in: 3.hours
  attributes :id, :rooms, :bathrooms, :price, :price_cents

  belongs_to :user
end

Это мой UserSerializer:

class UserSerializer < ActiveModel::Serializer
  cache key: 'user'
  attributes :id, :name, :email
  has_many :rental_units

  def name
    names = object.name.split(" ")
    "#{names[0].first}. #{names[1]}"
  end
end

Это часть моего Gemfile:

    source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '>= 5.0.0.beta3', '< 5.1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use Puma as the app server
gem 'puma'
gem 'active_model_serializers', '~> 0.10.0.rc1'
gem "dalli"
gem "memcachier"

А это мой файл config/environments/development.rb:

Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes = false

  # Do not eager load code on boot.
  config.eager_load = false

  # Show full error reports.
  config.consider_all_requests_local = true

  # Enable/disable caching. By default caching is disabled.
  if Rails.root.join('tmp/caching-dev.txt').exist?
    config.action_controller.perform_caching = true

    config.action_mailer.perform_caching = false

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => 'public, max-age=172800'
    }
  else
    config.action_controller.perform_caching = true

    config.action_mailer.perform_caching = false

    config.cache_store = :memory_store
  end

  # Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = false

  # Print deprecation notices to the Rails logger.
  config.active_support.deprecation = :log

  # Raise an error on page load if there are pending migrations.
  config.active_record.migration_error = :page_load


  # Raises error for missing translations
  # config.action_view.raise_on_missing_translations = true

  # Use an evented file watcher to asynchronously detect changes in source code,
  # routes, locales, etc. This feature depends on the listen gem.
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end

Вот странное поведение

Когда я посещаю http://localhost:3000/users, это мои журналы без признаков кэширования:

Started GET "/users" for ::1 at 2016-03-04 15:18:12 -0500
Processing by UsersController#index as HTML
  User Load (0.1ms)  SELECT "users".* FROM "users"
[active_model_serializers]   RentalUnit Load (0.2ms)  SELECT "rental_units".* FROM "rental_units" WHERE "rental_units"."user_id" = ?  [["user_id", 1]]
[active_model_serializers]   RentalUnit Load (0.1ms)  SELECT "rental_units".* FROM "rental_units" WHERE "rental_units"."user_id" = ?  [["user_id", 2]]
[active_model_serializers]   RentalUnit Load (0.1ms)  SELECT "rental_units".* FROM "rental_units" WHERE "rental_units"."user_id" = ?  [["user_id", 3]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModel::Serializer::Adapter::JsonApi (11.0ms)
Completed 200 OK in 13ms (Views: 12.5ms | ActiveRecord: 0.5ms)

Когда я захожу на http://localhost:3000/rental_units, есть ли кеширование?

Started GET "/rental_units" for ::1 at 2016-03-04 15:18:37 -0500
Processing by RentalUnitsController#index as HTML
  RentalUnit Load (0.4ms)  SELECT "rental_units".* FROM "rental_units"
[active_model_serializers]   User Load (0.9ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
[active_model_serializers]   CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
[active_model_serializers]   CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
[active_model_serializers]   User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModel::Serializer::Adapter::JsonApi (16.1ms)
Completed 200 OK in 21ms (Views: 19.1ms | ActiveRecord: 1.4ms)

Что здесь происходит? Похоже в последних логах кешируются пользователи? Я полагаю, что, поскольку 3 разных арендуемых единицы принадлежат Пользователю 1, AMS использует кэширование по умолчанию, когда идентичные SQL-запросы просто попадают в какой-то кеш. Таким образом, первый запрос для User1 попадает в базу данных сервера, а последующие запросы для User1 — нет. Где этот кеш? Это на сервере? Или какой-то веб-сервер?

Но я думаю, что моя стратегия кэширования в сериализаторе вообще не работает. Почему?


person Jwan622    schedule 04.03.2016    source источник


Ответы (2)


Чтобы облегчить отладку, попробуйте установить logger для своего кеша. Кэш Rails поддерживает настройку регистратора, но MemoryStore не устанавливает его по умолчанию.

В инициализаторе попробуйте следующее:

# config/initializers/cache.rb
Rails.cache.logger = Logger.new(STDOUT)
# or Rails.cache.logger = Rails.logger

Перезапустите сервер Rails, и вы должны увидеть ведение журнала попаданий/промахов в кеш. Я подозреваю, что это работает, но, возможно, не так, как вы ожидали.


Поскольку вы спросили, на самом деле есть пара уровней кэширования, которые затрагивает ваш вопрос: кэширование фрагментов (или представлений) и кэширование запросов.

Вы включили кеш как :memory_store, который создаст экземпляр ActiveSupport::Cache::MemoryStore, доступный в вашем приложении и в консоли Rails как Rails.cache.

Вы также установили cache параметры для вашего сериализатора. Из руководств ActiveModelSerializer для вашей версии похоже, вы правильно настроили это. Все идет нормально.

Как правило, в контроллере Rails кэш Rails не вызывается до тех пор, пока вы не перейдете к визуализации представления. В вашем случае вы визуализируете представление json (через AMS); это будет работать так же с шаблоном HTML.

При первом выполнении этого запроса кеш холодный, выполняется запрос БД, Rails запрашивает у кеша представление строки (строк) JSON с использованием ключа (или ключей) кеша. Поскольку кеш для этого набора ресурсов пуст, необходимо сгенерировать строку JSON, затем она кэшируется в Rails.cache, после чего возвращается ответ.

В следующий раз, когда будет сделан этот запрос (в течение окна истечения срока действия), будет сделан запрос к БД — Rails нужно знать, для каких ресурсов правильно запрашивать кеш? - и на этот раз кеш попадает, и строка возвращается из кеша. Нет необходимости создавать новый JSON. Обратите внимание, что это по-прежнему вызывает обращение к базе данных для запроса исходных ресурсов. Эти запросы необходимы AMS для поиска ключей кэша для вашего JSON.

Вы также видите CACHE select ... запросов в своих журналах. Как упоминалось в другом ответе, это может указывать на то, что вы делаете один и тот же запрос к БД снова и снова (часто указывает на запрос N+1), отсюда и предложение "нетерпеливо загрузить" эти отношения. Ваш RentalUnit принадлежит :user, поэтому для каждой арендуемой единицы делается отдельный запрос для каждого пользователя - возможно, вы сможете захватить всех этих пользователей одним запросом с жадной загрузкой.

Rails предоставляет некоторую возможность кэшировать результаты SQL-запросов. Это отличается от кэширования представлений, которое мы обсуждали, которое вы включили для AMS.

person rossta    schedule 07.03.2016

Я пробовал все вышеперечисленные ответы безрезультатно. В конце концов я просто оказался rm -rf ./tmp/cache в корне моего проекта.

person Gregory Ray    schedule 16.11.2020