Модель данных
Сохранённое значение — это одна строка «компания + ключ + значение».
Пара «компания + ключ» уникальна: у компании не может быть двух значений одного параметра. Ключи, по которым строки нет, работают на значении по умолчанию из реестра — то есть отсутствие строки это не ошибка, а нормальное состояние.
Таблица сохранённых значений — общая для всей платформы: она лежит в общей области данных, а не внутри данных каждой компании, и разделение обеспечивается колонкой «Компания». Это исключение из общей схемы разделения данных, описанной в «Разделение данных компаний и фоновая обработка».
Закодированное значение и его последствия
Значение сохраняется как единый слепок объекта, закодированный в текст (без сжатия, с фиксированной версией формата; исходный объект перед сохранением копируется, чтобы его нельзя было испортить). Плюс — в настройке можно хранить сложные структуры вроде списка вариантов штрафов с длительностями или раскладки карточки аренды. Минус — по значению почти нельзя искать в базе: разрешены только точное совпадение, перечисление вариантов и проверка «значение задано/не задано», а любое другое сравнение (больше, меньше, вхождение подстроки, сортировка, суммирование) завершается ошибкой. И даже точное совпадение сравнивает не смысл, а закодированное представление.Значение по умолчанию против сохранённого
Чтение даёт «сохранённое значение, если оно есть, иначе значение по умолчанию». Признаком «значения нет» служит только отсутствие значения в строке. Пустая строка, ноль, выключенный флаг — это полноценные сохранённые значения: они возвращаются как есть. Запись по ключу, которого нет в реестре, невозможна — попытка завершается ошибкой. Массовое обновление сначала проверяет весь переданный набор ключей и только потом начинает писать.Как читается настройка
Точка доступа к настройкам — ленивый объект настроек: он общий на весь процесс и создаётся при первом обращении, а не при запуске приложения (иначе приложение лезло бы в базу ещё до того, как известно, с какой компанией работает запрос). Собственного состояния у него нет: всё зависит от того, в контексте какой компании выполняется текущий код. В тот же момент — при первом обращении — подключается и автоматический сброс кэша при изменении строки настройки. Порядок разрешения одного значения:- Нет контекста компании — чтение сразу возвращает пусто, и вызывающий код получает значение по умолчанию.
- Кэш. Имя ключа складывается из идентификатора компании, подчёркивания и имени настройки (плюс общий префикс имён, по умолчанию пустой); сверху общий механизм кэша добавляет к ключу имя области данных текущей компании. Если значение найдено — оно и возвращается.
- Промах — попытка прогрева. Хранилище пробует разложить по кэшу сразу все настройки компании и читает ключ повторно.
- Всё ещё пусто — база. Делается точечный запрос за одной строкой. Результат кладётся в кэш «только если там ещё пусто», чтобы не затереть значение, которое параллельно успел записать кто-то другой. Если строки нет, в кэш попадает пустое значение — при следующем чтении это неотличимо от промаха.
- Строки нет — берётся значение по умолчанию, и оно тут же сохраняется в базу (см. предупреждение выше).
Каждое обращение к настройке — это отдельный поход в кэш. Результат не запоминается в пределах запроса, поэтому обработчик, читающий полтора десятка настроек, делает полтора десятка обращений к кэшу. Это дёшево, но не бесплатно, и именно поэтому прогрев так важен.
Прогрев кэша
Прогрев — главный приём этого модуля: вместо того чтобы ходить в базу за каждым ключом, хранилище одним запросом достаёт все сохранённые значения компании и раскладывает их по кэшу.- Срок жизни разложенных значений — сутки (настраиваемый параметр модуля).
- Рядом кладётся служебная метка прогрева. Пока она жива, повторный прогрев не выполняется, даже если конкретного ключа в кэше нет.
- Если срок жизни выставлен в ноль, прогрев отключается полностью и всё читается точечно.
- Вне контекста компании прогрев молча пропускается.
Как записывается настройка
Одиночная запись
Запись одного значения делает три вещи подряд: сохраняет строку в базе (создаёт или обновляет), при обновлении существующей строки автоматически запускается полный сброс кэша компании, а затем новое значение кладётся в кэш. Порядок важен: сброс происходит до записи свежего значения, поэтому новое значение переживает собственную инвалидацию. При создании новой строки сброс пропускается.Массовое обновление
Сохранение целой формы настроек идёт иначе, чтобы не сбрасывать кэш сотню раз подряд:- включается подавление реакций на сохранение — автоматические обработчики на время записи замолкают;
- значения пишутся по одному в базу, но уже без побочных эффектов;
- подавление снимается, и выполняется один полный сброс кэша компании;
- свежие значения раскладываются по кэшу.
На последнем шаге значения раскладываются дважды: сначала под правильными именами (с идентификатором компании), затем ещё раз под именами без идентификатора. Второй набор ключей никем не читается — это лишние записи в кэш, по одной на каждое сохранённое значение.
Полный сброс
Сброс работает по идентификатору компании: он удаляет из кэша ключи всех настроек реестра плюс метку прогрева, после чего сразу же запускает прогрев заново. То есть цена изменения одной настройки — удаление порядка ста двадцати ключей, один запрос в базу за всеми значениями компании и повторная раскладка их по кэшу.Сброс перебирает именно ключи реестра. Значение по ключу, который из реестра убрали, останется в базе, не будет вычищено из кэша и не будет попадать в прогрев.
Автоматическая реакция на сохранение
На сохранение строки настройки подписаны две реакции, и они делают разное:
Пропуск сброса при создании строки — не оплошность: новой строки в кэше по определению ещё нет, а свежее значение вызывающий код запишет туда сам.
Сброс кэша при изменении строки подключается в тот момент, когда процесс впервые обращается к настройкам через хранилище. Процесс, который только пишет строки настроек и ни разу их не читал, этой реакции не имеет.
Сроки жизни записей в кэше
Асимметрия здесь не случайна, но её последствия стоит понимать. Только что изменённая настройка живёт в кэше пятнадцать секунд, а метка прогрева — сутки. Поэтому после того как короткий срок истечёт, повторный прогрев не запустится (метка ещё жива), и каждое обращение к этой настройке будет уходить в базу отдельным запросом — до тех пор, пока не истекут сутки и кэш не прогреется целиком заново. На корректность это не влияет, на нагрузку — немного да.
Поведение вне контекста компании
Когда код выполняется не от имени конкретной компании, вместо неё подставляется заглушка компании. Хранилище настроек реагирует на неё предельно тихо:- чтение возвращает пусто — а значит, вызывающий код получает значение по умолчанию из реестра;
- запись молча игнорируется, ошибки не будет;
- прогрев пропускается;
- сброс кэша удалит ключи, но повторный прогрев тут же завершится ничем.
Устойчивость к сбоям
Все обращения модуля к кэшу идут через обёртки безопасной работы с кэшем: при любой ошибке кэша в журнал пишется предупреждение, а вызов возвращает значение по умолчанию или признак неуспеха. Ни чтение, ни запись настройки не роняют запрос из-за недоступного кэша. Точно так же подавляются и ошибки базы при чтении: если запрос за настройками не проходит (например, во время миграций), вместо исключения система просто останется на значениях по умолчанию.Как это используется
- Бизнес-логика — аренды, клиенты, инвентарь, метрики, фоновые задачи — читает настройки, как правило, через ленивый объект настроек, то есть через описанную выше цепочку «кэш → прогрев → база → значение по умолчанию».
- Часть фоновых задач и интеграций обращается к строкам напрямую: отбирает компании по сохранённому значению настройки или включает возможности, записывая строки. Такие обращения идут мимо кэша и находят только те компании, у которых строка действительно сохранена.
- Страница настроек в API читает значения иначе: она берёт значения по умолчанию из реестра и накладывает поверх сохранённые строки компании напрямую из базы, минуя кэш. Сохранение с этой же страницы идёт через массовое обновление, то есть с одним сбросом кэша в конце.
- Платформенная админка пишет строки настроек напрямую, по одному ключу за раз, и умеет удалять строку целиком («сбросить настройку»).
- Создание компании сразу записывает несколько значений строками в базу: «Название организации», «Адрес организации», «Валюта» и «Язык компании» — остальное компания получает на значениях по умолчанию.
- Подключение платных модулей включает связанные с ними возможности, записывая строки настроек напрямую.
Подводные камни
Менее критичные особенности, о которых стоит знать:- Реакция на сохранение кладёт значение в кэш под именем ключа без идентификатора компании, а чтение ищет ключ с идентификатором. Эта запись никем не читается, зато в большинстве случаев требует дополнительно подтянуть из базы компанию-владельца.
- Массовое сохранение раскладывает свежие значения по кэшу дважды: под правильными именами и ещё раз под именами без идентификатора компании. Второй набор ключей никем не читается.
- Прогрев кладёт значения на сутки, а точечная запись и чтение из базы — на общий короткий срок кэша проекта (15 секунд). Поскольку метка прогрева живёт сутки, только что изменённая настройка после этих 15 секунд читается из базы отдельным запросом при каждом обращении.
- Прогрев раскладывает по кэшу только ключи, по которым уже есть сохранённые строки. Ключи на значениях по умолчанию метка прогрева не покрывает, и каждое обращение к ним уходит в базу, пока первое чтение не создаст строку.
- Массовое сохранение не обёрнуто в транзакцию и сбрасывает кэш только в самом конце: обрыв на середине оставит часть значений в базе, а кэш — со старыми.
- Сброс кэша и прогрев перебирают только ключи из реестра, поэтому значение по ключу, убранному из реестра, останется в базе, не будет вычищено из кэша и не попадёт в прогрев.
- Массовое сохранение из платформенной админки идёт по одному ключу и без подавления реакций: каждое изменённое поле запускает отдельный сброс, который к тому же чистит ключи не в той области данных.
- Автоматический сброс кэша при изменении строки подключается в момент первого обращения к настройкам через хранилище в данном процессе. Процесс, который только пишет строки и ни разу их не читал, этой реакции не имеет.
- Ошибки кэша и ошибки базы при чтении подавляются с записью предупреждения в журнал, поэтому сбой хранилища внешне выглядит как самопроизвольный сброс настроек компании, а не как авария.
Дополнительные наблюдения:
- Страница настроек в API читает значения напрямую из базы, минуя кэш, поэтому она может показывать уже новое значение, тогда как бизнес-логика ещё применяет закэшированное старое.
- Значение хранится закодированным слепком в текстовой колонке, и по нему разрешены только точное совпадение, перечисление вариантов и проверка «задано/не задано»; любое другое сравнение завершается ошибкой.
- Тип значения указан не у всех ключей реестра: часть записей содержит только значение по умолчанию и подпись, а тип выводится из значения по умолчанию.
- Каждое обращение к настройке — отдельный поход в кэш: результат не запоминается в пределах запроса, поэтому обработчик, читающий десяток настроек, делает десяток обращений.
- При создании компании четыре настройки — название, адрес, валюта и язык — записываются строками напрямую, минуя обычный слой записи; подключение платных модулей точно так же напрямую включает связанные возможности.
Связанные страницы
Глоссарий: Хранение и кэш настроек
Полный перечень полей и терминов слоя хранения настроек.
Настройки компании
Обзорная страница модуля со всеми его разделами.
Реестр настроек компании
Полный перечень параметров компании: что можно включить или выключить, какие значения стоят по умолчанию и как настройки читаются и сохраняются.
Дополнительные поля
Собственные поля компании для клиентов, инвентаря, аренд и других справочников: типы, обязательность, отображение в таблице и фильтрах.
Переименование сущностей
Как компания меняет названия разделов и статусов под свою нишу, включая формы слова по падежам и числам.
Настройки таблиц
Сохранённый состав, порядок и ширина колонок для таблиц интерфейса — отдельно по каждой таблице компании.
Промо-баннеры
Показ рекламных и информационных баннеров платформы внутри системы: частота показа, отметка о просмотре и исключение компаний.
Сквозная автонумерация
Общий счётчик компании, из которого берутся номера клиентов, артикулы создаваемых единиц инвентаря и номера документов.
Настройки в админ-панели
Служебный экран платформы для просмотра и правки настроек конкретной компании со сбросом значений к умолчанию.