Skip to main content
Полный перечень полей — в глоссарии хранения и кэша настроек. Настройки компании существуют в двух слоях. Первый — реестр настроек компании: заданный в коде список всех известных системе параметров, где у каждого ключа записаны значение по умолчанию, служебная подпись и (не у всех ключей) тип значения; там, где тип не указан, он выводится из значения по умолчанию. Второй — сохранённые значения: строки в базе, которые компания завела для тех ключей, где её решение отличается от значения по умолчанию. Между кодом и этими двумя слоями стоит хранилище настроек — оно решает, откуда взять значение, держит горячую копию в кэше и сбрасывает её при изменениях. Всего в реестре порядка ста двадцати ключей.

Модель данных

Сохранённое значение — это одна строка «компания + ключ + значение». Пара «компания + ключ» уникальна: у компании не может быть двух значений одного параметра. Ключи, по которым строки нет, работают на значении по умолчанию из реестра — то есть отсутствие строки это не ошибка, а нормальное состояние.
Таблица сохранённых значений — общая для всей платформы: она лежит в общей области данных, а не внутри данных каждой компании, и разделение обеспечивается колонкой «Компания». Это исключение из общей схемы разделения данных, описанной в «Разделение данных компаний и фоновая обработка».

Закодированное значение и его последствия

Значение сохраняется как единый слепок объекта, закодированный в текст (без сжатия, с фиксированной версией формата; исходный объект перед сохранением копируется, чтобы его нельзя было испортить). Плюс — в настройке можно хранить сложные структуры вроде списка вариантов штрафов с длительностями или раскладки карточки аренды. Минус — по значению почти нельзя искать в базе: разрешены только точное совпадение, перечисление вариантов и проверка «значение задано/не задано», а любое другое сравнение (больше, меньше, вхождение подстроки, сортировка, суммирование) завершается ошибкой. И даже точное совпадение сравнивает не смысл, а закодированное представление.

Значение по умолчанию против сохранённого

Чтение даёт «сохранённое значение, если оно есть, иначе значение по умолчанию». Признаком «значения нет» служит только отсутствие значения в строке. Пустая строка, ноль, выключенный флаг — это полноценные сохранённые значения: они возвращаются как есть.
Чтение настройки, у которой ещё нет сохранённого значения, само создаёт строку со значением по умолчанию. То есть обычный просмотр данных компании постепенно материализует в базе весь реестр: сначала строк нет ни одной, через какое-то время работы их столько, сколько разных настроек успела прочитать система.
Сохранение со страницы настроек подменяет любое «пустое» значение на пустой текст: выключенный флаг, ноль, нулевая длительность и пустой список записываются в базу одинаково — пустой строкой. Чаще всего это проходит незаметно, потому что пустая строка ведёт себя как «выключено», а страница настроек умеет показывать её обратно как ноль или нулевую длительность. Но код, которому нужно именно число, получает текст: при нулевом округлении штрафа пересчёт падает на преобразовании значения. А прямые проверки по базе вида «настройка выключена» такие строки не находят, потому что ищут логическое «нет», а не пустой текст.
Запись по ключу, которого нет в реестре, невозможна — попытка завершается ошибкой. Массовое обновление сначала проверяет весь переданный набор ключей и только потом начинает писать.

Как читается настройка

Точка доступа к настройкам — ленивый объект настроек: он общий на весь процесс и создаётся при первом обращении, а не при запуске приложения (иначе приложение лезло бы в базу ещё до того, как известно, с какой компанией работает запрос). Собственного состояния у него нет: всё зависит от того, в контексте какой компании выполняется текущий код. В тот же момент — при первом обращении — подключается и автоматический сброс кэша при изменении строки настройки. Порядок разрешения одного значения:
  1. Нет контекста компании — чтение сразу возвращает пусто, и вызывающий код получает значение по умолчанию.
  2. Кэш. Имя ключа складывается из идентификатора компании, подчёркивания и имени настройки (плюс общий префикс имён, по умолчанию пустой); сверху общий механизм кэша добавляет к ключу имя области данных текущей компании. Если значение найдено — оно и возвращается.
  3. Промах — попытка прогрева. Хранилище пробует разложить по кэшу сразу все настройки компании и читает ключ повторно.
  4. Всё ещё пусто — база. Делается точечный запрос за одной строкой. Результат кладётся в кэш «только если там ещё пусто», чтобы не затереть значение, которое параллельно успел записать кто-то другой. Если строки нет, в кэш попадает пустое значение — при следующем чтении это неотличимо от промаха.
  5. Строки нет — берётся значение по умолчанию, и оно тут же сохраняется в базу (см. предупреждение выше).
Каждое обращение к настройке — это отдельный поход в кэш. Результат не запоминается в пределах запроса, поэтому обработчик, читающий полтора десятка настроек, делает полтора десятка обращений к кэшу. Это дёшево, но не бесплатно, и именно поэтому прогрев так важен.

Прогрев кэша

Прогрев — главный приём этого модуля: вместо того чтобы ходить в базу за каждым ключом, хранилище одним запросом достаёт все сохранённые значения компании и раскладывает их по кэшу.
  • Срок жизни разложенных значений — сутки (настраиваемый параметр модуля).
  • Рядом кладётся служебная метка прогрева. Пока она жива, повторный прогрев не выполняется, даже если конкретного ключа в кэше нет.
  • Если срок жизни выставлен в ноль, прогрев отключается полностью и всё читается точечно.
  • Вне контекста компании прогрев молча пропускается.
Прогрев запускается в трёх случаях: при создании хранилища (то есть при самом первом обращении к настройкам в процессе), при промахе кэша и после каждого полного сброса.
Прогрев раскладывает по кэшу только те ключи, по которым уже есть сохранённые строки. Ключи, живущие на значении по умолчанию, метка прогрева не покрывает: пока их первое чтение не создаст строку, каждое обращение к ним будет уходить в базу отдельным запросом.

Как записывается настройка

Одиночная запись

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

Массовое обновление

Сохранение целой формы настроек идёт иначе, чтобы не сбрасывать кэш сотню раз подряд:
  1. включается подавление реакций на сохранение — автоматические обработчики на время записи замолкают;
  2. значения пишутся по одному в базу, но уже без побочных эффектов;
  3. подавление снимается, и выполняется один полный сброс кэша компании;
  4. свежие значения раскладываются по кэшу.
Подавление действует только внутри текущего запроса или фоновой задачи и не влияет на параллельную работу других.
На последнем шаге значения раскладываются дважды: сначала под правильными именами (с идентификатором компании), затем ещё раз под именами без идентификатора. Второй набор ключей никем не читается — это лишние записи в кэш, по одной на каждое сохранённое значение.
Массовое сохранение не обёрнуто в общую транзакцию, а кэш сбрасывается только в самом конце. Если запись оборвётся на середине, часть значений уже окажется в базе, а кэш ещё будет отдавать старые — до истечения срока жизни записей.

Полный сброс

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

Автоматическая реакция на сохранение

На сохранение строки настройки подписаны две реакции, и они делают разное: Пропуск сброса при создании строки — не оплошность: новой строки в кэше по определению ещё нет, а свежее значение вызывающий код запишет туда сам.
Вторая реакция кладёт значение в кэш под именем ключа без идентификатора компании, тогда как чтение ищет ключ с идентификатором. Эта запись фактически никем не читается, зато в большинстве случаев требует дополнительно подтянуть из базы компанию-владельца. Реальную инвалидацию делает только сброс кэша в хранилище.
Сброс кэша при изменении строки подключается в тот момент, когда процесс впервые обращается к настройкам через хранилище. Процесс, который только пишет строки настроек и ни разу их не читал, этой реакции не имеет.

Сроки жизни записей в кэше

Асимметрия здесь не случайна, но её последствия стоит понимать. Только что изменённая настройка живёт в кэше пятнадцать секунд, а метка прогрева — сутки. Поэтому после того как короткий срок истечёт, повторный прогрев не запустится (метка ещё жива), и каждое обращение к этой настройке будет уходить в базу отдельным запросом — до тех пор, пока не истекут сутки и кэш не прогреется целиком заново. На корректность это не влияет, на нагрузку — немного да.

Поведение вне контекста компании

Когда код выполняется не от имени конкретной компании, вместо неё подставляется заглушка компании. Хранилище настроек реагирует на неё предельно тихо:
  • чтение возвращает пусто — а значит, вызывающий код получает значение по умолчанию из реестра;
  • запись молча игнорируется, ошибки не будет;
  • прогрев пропускается;
  • сброс кэша удалит ключи, но повторный прогрев тут же завершится ничем.
Это самая опасная особенность модуля. Код, который переключил только область данных, но не контекст компании, увидит не настройки компании, а значения по умолчанию: выключенными окажутся штрафы, бонусы и налог, а валюта и цвета статусов станут стандартными. Ошибки при этом не будет ни одной. Общая механика контекста компании описана в «Разделение данных компаний и фоновая обработка».
Отдельный случай той же природы — платформенная админка: она работает вне контекста конкретной компании, а ключи кэша дополнительно разделены по области данных. Поэтому правка настроек компании из админки чистит ключи «не той» области, повторный прогрев там завершается ничем, и компания продолжает читать старое значение до истечения срока жизни записи — то есть в худшем случае до суток.

Устойчивость к сбоям

Все обращения модуля к кэшу идут через обёртки безопасной работы с кэшем: при любой ошибке кэша в журнал пишется предупреждение, а вызов возвращает значение по умолчанию или признак неуспеха. Ни чтение, ни запись настройки не роняют запрос из-за недоступного кэша. Точно так же подавляются и ошибки базы при чтении: если запрос за настройками не проходит (например, во время миграций), вместо исключения система просто останется на значениях по умолчанию.
Обратная сторона: недоступность кэша или базы внешне выглядит как «у компании сбросились настройки» — возможности выключаются, валюта и цвета возвращаются к стандартным. Первым делом стоит смотреть предупреждения в журнале, а не искать, кто изменил настройки.

Как это используется

  • Бизнес-логика — аренды, клиенты, инвентарь, метрики, фоновые задачи — читает настройки, как правило, через ленивый объект настроек, то есть через описанную выше цепочку «кэш → прогрев → база → значение по умолчанию».
  • Часть фоновых задач и интеграций обращается к строкам напрямую: отбирает компании по сохранённому значению настройки или включает возможности, записывая строки. Такие обращения идут мимо кэша и находят только те компании, у которых строка действительно сохранена.
  • Страница настроек в API читает значения иначе: она берёт значения по умолчанию из реестра и накладывает поверх сохранённые строки компании напрямую из базы, минуя кэш. Сохранение с этой же страницы идёт через массовое обновление, то есть с одним сбросом кэша в конце.
  • Платформенная админка пишет строки настроек напрямую, по одному ключу за раз, и умеет удалять строку целиком («сбросить настройку»).
  • Создание компании сразу записывает несколько значений строками в базу: «Название организации», «Адрес организации», «Валюта» и «Язык компании» — остальное компания получает на значениях по умолчанию.
  • Подключение платных модулей включает связанные с ними возможности, записывая строки настроек напрямую.
Если изменение настройки «не подействовало», проверяйте в таком порядке: сохранилась ли строка в базе (страница настроек показывает именно её), не сбрасывался ли кэш в чужой области данных (правка из платформенной админки или удаление строки), и не читается ли настройка кодом, работающим вне контекста компании.

Подводные камни

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

Связанные страницы

Глоссарий: Хранение и кэш настроек

Полный перечень полей и терминов слоя хранения настроек.

Настройки компании

Обзорная страница модуля со всеми его разделами.

Реестр настроек компании

Полный перечень параметров компании: что можно включить или выключить, какие значения стоят по умолчанию и как настройки читаются и сохраняются.

Дополнительные поля

Собственные поля компании для клиентов, инвентаря, аренд и других справочников: типы, обязательность, отображение в таблице и фильтрах.

Переименование сущностей

Как компания меняет названия разделов и статусов под свою нишу, включая формы слова по падежам и числам.

Настройки таблиц

Сохранённый состав, порядок и ширина колонок для таблиц интерфейса — отдельно по каждой таблице компании.

Промо-баннеры

Показ рекламных и информационных баннеров платформы внутри системы: частота показа, отметка о просмотре и исключение компаний.

Сквозная автонумерация

Общий счётчик компании, из которого берутся номера клиентов, артикулы создаваемых единиц инвентаря и номера документов.

Настройки в админ-панели

Служебный экран платформы для просмотра и правки настроек конкретной компании со сбросом значений к умолчанию.