Ошибки базы данных кэшируются 30 минут в client_settings_json — сайт не загружается

Приоритет/Серьезность

Редко, но критично: сайт становится неработоспособным до 30 минут после временных ошибок базы данных. Страницы не загружаются корректно из-за отсутствующих настроек клиента, что вызывает ошибки JavaScript.

Платформа

  • Затрагивает: все установки Discourse
  • Наблюдается в: производственных средах, испытывающих временные проблемы с подключением к базе данных

Описание

Фактический результат
При возникновении временной ошибки базы данных (тайм-аут подключения, исчерпание пула соединений, сетевой сбой) ошибка кэшируется на 30 минут. В это время:

  • Сайт не загружается корректно — страницы выглядят сломанными или неработоспособными
  • Возникают ошибки клиентского JavaScript из-за отсутствующих/некорректных настроек
  • Каждый запрос логирует сообщение: «Nil client_settings_json from the cache for ‘client_settings_json_[git_version]’»
  • Браузеру возвращаются пустые настройки клиента
  • Это продолжается даже после полного восстановления базы данных

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

Шаги для воспроизведения

  1. Запустите экземпляр Discourse с настроенными настройками клиента.
  2. Симулируйте проблему с подключением к базе данных (например, исчерпайте пул соединений, добавьте задержку сети или временно заблокируйте порт 5432).
  3. Выполните запрос, вызывающий SiteSetting.client_settings_json (для этого подойдет загрузка любой страницы).
  4. Наблюдайте ошибку: «Error while generating client_settings_json_uncached: [database error]».
  5. Страницы не рендерятся корректно, консоль JavaScript показывает ошибки, связанные с отсутствующими настройками.
  6. Восстановите подключение к базе данных.
  7. Выполняйте дополнительные запросы в течение следующих 30 минут. Продолжайте видеть ошибки «Nil client_settings_json from the cache», несмотря на исправную базу данных.
  8. Через 30 минут кэш истекает, и сайт наконец восстанавливается.

Влияние на пользователя

В этот период сайт фактически неработоспособен:

  • Страницы не рендерятся корректно
  • JavaScript-приложения не инициализируются из-за отсутствия конфигурации

Это превращает 1-секундный сбой базы данных в 30-минутный простой.

Первопричина

В файле lib/site_setting_extension.rb метод client_settings_json_uncached перехватывает исключения и возвращает nil. Этот nil кэшируется на 30 минут, ломая сайт.

Предлагаемое исправление

Для решения этой проблемы был отправлен pull request. Исправление требует простого изменения: вместо возврата nil нужно снова выбрасывать исключение.

Почему это работает:

  1. Повторная выброска исключения предотвращает кэширование ошибки через Discourse.cache.fetch.
  2. Внешний метод client_settings_json уже имеет корректную обработку исключений, которая возвращает «» (пустую строку) без её кэширования.
  3. Сайт продолжает функционировать во время проблем с базой данных (хотя и с ухудшенной производительностью).
  4. Сайт автоматически восстанавливается при следующем запросе, как только база данных станет исправной.
  5. Исправление гарантирует, что временные ошибки базы данных не вызовут 30-минутные простои.

Влияние

Эта ошибка затрагивает все установки Discourse, испытывающие временные проблемы с базой данных:

  • Исчерпание пула соединений во время пиков трафика
  • Сетевые сбои между приложением и базой данных
  • Сценарии переключения базы данных (например, переключение между главным и репликой)
  • Конфликт блокировок в таблице site_settings
  • Тайм-ауты запросов из-за медленных запросов

Серьезность: Любая из этих распространенных временных проблем приводит к тому, что весь сайт становится неработоспособным на 30 минут, даже если основная проблема разрешается за секунды.

Обходной путь

Если вы столкнулись с этой проблемой прямо сейчас, вы можете вручную очистить кэш для восстановления работы:

В консоли Rails

Discourse.cache.delete(SiteSettingExtension.client_settings_cache_key)
2 лайка

Отлично подмечено, я посмотрю ваш PR.

5 лайков

Похоже, что это уже объединили, большое спасибо.

2 лайка