В процессе разработки и настройки типовых конфигураций 1С (таких как 1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей и других решений на базе Библиотеки стандартных подсистем — БСП) программисты и администраторы часто сталкиваются с неочевидным поведением механизма напоминаний. Типичная ситуация: пользователь устанавливает напоминание, время события наступает, но заветное всплывающее окно появляется лишь спустя 10–15 минут или не появляется вовсе до совершения определенных действий в программе. Еще сложнее обстоит дело, когда один пользователь программно или интерактивно создает напоминание для другого пользователя.
В этой статье мы подробно разберем, как устроен механизм напоминаний БСП «под капотом», проанализируем причины возникновения задержек и рассмотрим практические способы решения этой проблемы как для текущего пользователя, так и при взаимодействии между разными сеансами.
Для начала проанализируем стандартную архитектуру подсистемы напоминаний БСП. Все созданные напоминания физически записываются и хранятся в регистре сведений НапоминанияПользователя. На стороне клиентского приложения за своевременный вывод окон оповещений отвечает специальный обработчик ожидания, который подключается при старте системы.
Периодичность срабатывания этого обработчика определяется внутренними настройками системы и обычно составляет 60 секунд. Каждую минуту клиентское приложение обращается к серверу, вызывая функцию НапоминанияПользователяКлиент.ПолучитьТекущиеОповещения(), чтобы проверить, появились ли новые напоминания, время которых уже наступило.
Казалось бы, при ежеминутной проверке задержка в отображении напоминаний не должна превышать одной минуты. Однако на практике интервал может составлять до 15–20 минут. Выясним, почему так происходит.
Разработчики фирмы «1С» заложили в БСП жесткую оптимизацию производительности. Если бы каждый активный пользователь каждую минуту делал прямой запрос к базе данных и физической таблице регистра сведений НапоминанияПользователя, это создало бы колоссальную паразитную нагрузку на СУБД, особенно в крупных информационных базах со многими сотнями одновременно работающих сотрудников.
Чтобы снизить нагрузку, был разработан следующий алгоритм оптимизации:
НапоминанияПользователяКлиентПовтИсп.ПолучитьНапоминанияТекущегоПользователя().В чем заключается проблема? Если в течение этих 30 минут в базу данных записывается новое напоминание (например, его программно создал фоновый процесс или другой пользователь базы данных), то локальный кэш текущего пользователя об этом изменении ничего не знает. Для него этого напоминания просто не существует в памяти. Система отобразит его только тогда, когда кэш повторного использования устареет и сбросится автоматически (обычно это происходит через 20 минут), либо если пользователь принудительно совершит действие, инициирующее очистку кэша (например, сам создаст новое напоминание вручную через стандартную форму).
Рассмотрим подробнее программные способы обхода этого ограничения в зависимости от сценария работы.
Если код создания напоминания выполняется в сеансе того же пользователя, который и должен получить это напоминание, мы можем принудительно заставить систему пересчитать кэш. Посмотрим на три основных способа реализации этой задачи.
Способ 1. Точечное обновление записи в кэше
Это самый оптимальный и легкий способ с точки зрения производительности. Вместо полной очистки кэша мы сообщаем системе, что нужно добавить конкретную запись в локальный массив. Для этого используем стандартную процедуру БСП:
ПараметрыОповещения = Новый Структура;
ПараметрыОповещения.Вставить("Пользователь", ПараметрыНапоминания.Пользователь);
ПараметрыОповещения.Вставить("ВремяСобытия", ПараметрыНапоминания.ВремяСобытия);
ПараметрыОповещения.Вставить("Источник", ПараметрыНапоминания.Источник);
НапоминанияПользователяКлиент.ОбновитьЗаписьВКэшеОповещений(ПараметрыОповещения);
Способ 2. Принудительный сброс таймера проверок
Мы можем принудительно остановить текущий обработчик ожидания и запустить его заново, что спровоцирует мгновенное обращение к серверу за актуальными данными:
НапоминанияПользователяГлобальный.СброситьТаймерПроверкиТекущихОповещений();
Способ 3. Кардинальный сброс кэша повторного использования
Если требуется полностью очистить все кэшированные данные модулей повторного использования на клиенте, можно воспользоваться встроенным методом платформы:
ОбновитьПовторноИспользуемыеЗначения();
Важное замечание: Использование ОбновитьПовторноИспользуемыеЗначения() является крайне ресурсоемкой операцией. Данный метод сбрасывает кэш вообще всех модулей конфигурации, что может привести к кратковременному падению производительности клиентского приложения в момент следующего обращения к различным функциям. Рекомендуется использовать его только в крайних случаях.
Это наиболее сложный сценарий. Поскольку один пользователь работает в своем изолированном клиентском сеансе, он физически не может вызвать процедуру сброса кэша в оперативной памяти другого пользователя. Если пользователь А запишет напоминание для пользователя Б, то пользователь Б гарантированно получит задержку в отображении, пока его локальный кэш не обновится естественным образом.
Разберем три практических подхода к решению этой архитектурной проблемы.
Механизм напоминаний БСП проектировался как персональный органайзер (задачи самому себе) и изначально не предназначался для мгновенного обмена сообщениями. Если бизнес-требования диктуют необходимость моментальной доставки уведомлений коллегам, лучшим решением будет использование встроенного механизма платформы — Системы взаимодействия (обсуждений).
При отправке сообщения через Систему взаимодействия адресат получает push-уведомление мгновенно (в режиме реального времени), полностью минуя СУБД и клиентские кэши модулей 1С. Это современный стандарт реализации мгновенных оповещений.
Если необходимо сохранить работу именно через стандартный механизм напоминаний БСП, мы можем пойти на компромисс между производительностью и скоростью доставки. Для этого в расширении конфигурации можно изменить свойства общего модуля НапоминанияПользователяКлиентПовтИсп.
Если полностью отключить у этого модуля свойство «Повторное использование возвращаемых значений», то при каждом ежеминутном срабатывании таймера система будет выполнять реальный запрос к базе данных. Новые напоминания от других пользователей начнут приходить с задержкой не более одной минуты.
Внимание: Данный подход значительно увеличивает нагрузку на СУБД. Если в базе одновременно работают сотни пользователей, это может вызвать серьезные проблемы с производительностью системы.
В качестве альтернативы можно внедрить собственный некэшируемый обработчик ожидания в модуле управляемого приложения. Разберем этот алгоритм по шагам:
НапоминанияПользователя напрямую, минуя механизмы БСП, отбирая только записи для текущего пользователя со статусом «Не оповещен».
// Пример вызова в кастомном обработчике ожидания при обнаружении новых записей
НапоминанияПользователяГлобальный.СброситьТаймерПроверкиТекущихОповещений();
Таким образом, мы сохраняем оптимизацию БСП для обычного режима работы, но гарантируем, что внешние напоминания будут принудительно доставлены пользователю в пределах заданного нами небольшого интервала времени.