В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача оперативного оповещения всех работающих пользователей. Это может быть уведомление о предстоящем техническом обслуживании, просьба выйти из базы для обновления или информация о важных изменениях в бизнес-процессах. Основная сложность заключается в том, чтобы сообщение вывелось ровно один раз для каждого пользователя, не вызывало избыточной нагрузки на сервер и корректно обрабатывало ситуации, когда пользователь входит в систему позже появления уведомления.
В рамках этой статьи мы подробно разберем несколько стратегий реализации данной задачи: от классического использования регистров сведений до современных механизмов платформы.
Самый распространенный и интуитивно понятный способ — использование независимого регистра сведений. Рассмотрим, как правильно спроектировать структуру данных, чтобы избежать блокировок и лишней нагрузки.
Создадим независимый регистр сведений ОповещенияПользователей со следующей структурой:
Пользователь (Тип: СправочникСсылка.Пользователи).ИдентификаторСообщения (Тип: Строка или УникальныйИдентификатор).Просмотрено (Тип: Булево).ДатаПросмотра (Тип: Дата).Проанализируем алгоритм работы. При создании нового сообщения программно создаются записи в регистре для всех существующих пользователей с флагом Просмотрено = Ложь. На стороне клиента в модуле управляемого приложения мы подключаем обработчик ожидания.
// В модуле управляемого приложения
Процедура ПриНачалеРаботыСистемы()
ПодключитьОбработчикОжидания("ПроверитьНовыеОповещения", 60); // Проверка раз в минуту
КонецПроцедуры
Процедура ПроверитьНовыеОповещения() Экспорт
// Вызов серверного метода для проверки наличия непрочитанных сообщений
ДанныеОповещения = РаботаСОповещениямиСервер.ПолучитьНовоеОповещениеДляТекущегоПользователя();
Если ДанныеОповещения <> Неопределено Тогда
ПоказатьОповещениеПользователя("ВНИМАНИЕ!", , ДанныеОповещения.ТекстСообщения);
// Или выводим полноценное окно
Предупреждение(ДанныеОповещения.ТекстСообщения);
// Отмечаем прочтение
РаботаСОповещениямиСервер.ОтметитьПрочтение(ДанныеОповещения.Идентификатор);
КонецЕсли;
КонецПроцедуры
Разберем важный момент, упомянутый в обсуждении: блокировки. Чтобы избежать проблем при одновременном чтении и записи множеством сеансов, используйте Управляемый режим блокировок. Чтение должно выполняться максимально быстро. Если мы используем схему с удалением записи после прочтения (как предлагали некоторые участники форума), это может быть эффективнее по объему данных, но лишает нас истории ознакомления.
Постоянный опрос базы данных (polling) из сотен клиентских сеансов каждые 30-60 секунд может заметно нагрузить SQL-сервер. Чтобы оптимизировать этот процесс, применим кэширование через параметры сеанса.
Выясним причину эффективности этого метода: обращение к параметру сеанса происходит в памяти сервера приложений, что на порядки быстрее запроса к СУБД. Создадим параметр сеанса АктуальноеОповещениеПросмотрено (Булево).
Ложь, идем в базу, показываем сообщение и обновляем и параметр, и регистр.Посмотрим на пример серверного кода:
Функция НужноЛиИдтиВБазу() Экспорт
// Параметры сеанса работают очень быстро
Возврат НЕ ПараметрыСеанса.АктуальноеОповещениеПросмотрено;
КонецФункции
Один из участников предложил интересную альтернативу — использовать Справочник вместо регистра. Логика следующая: одна карточка справочника — это одно сообщение. В табличной части ОзнакомленныеПользователи фиксируются те, кто уже нажал кнопку «ОК».
Преимущества такого подхода:
Проанализируем ситуацию с массовым входом пользователей. Если одновременно 100 человек нажмут «Ознакомлен», запись в одну и ту же табличную часть одного элемента справочника может вызвать блокировку. Поэтому для записи отметки лучше использовать отдельный вспомогательный Регистр Сведений, который будет служить очередью для регламентного задания, переносящего отметки в справочник, либо использовать независимые записи регистра сразу.
Если ваша платформа версии 8.3.10 и выше, наиболее технологичным решением будет использование Системы взаимодействия. Это встроенный механизм, позволяющий реализовать Push-уведомления.
Рассмотрим, почему это лучше:
Для реализации нам понадобится использовать объект СистемаВзаимодействия. Пример отправки сообщения программно:
// На сервере
ВыбранныеПользователи = Новый Массив;
// Добавляем идентификаторы пользователей системы взаимодействия
// ...
НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(ОбсуждениеИд);
НовоеСообщение.Текст = "Внимание! Срочно сохраните данные, база будет отключена через 5 минут!";
НовоеСообщение.Записать();
На стороне клиента сработает обработчик ПриПолученииСообщенияСистемыВзаимодействия, в котором мы можем вызвать диалоговое окно.
Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), рассмотрите подсистему «Текущие дела» или механизмы заметок/напоминаний. В БСП уже реализованы механизмы рассылки уведомлений пользователям.
В частности, модуль ОповещенияПользователей позволяет создавать программные оповещения, которые всплывают в правом нижнем углу интерфейса «Такси». Это менее навязчиво, чем модальное окно Предупреждение, и соответствует современным стандартам UI-дизайна 1С.
Подводя итоги, выберем оптимальный путь в зависимости от условий:
РегистрСведений + ПодключитьОбработчикОжидания. Обязательно добавьте поле «Срок актуальности», чтобы старые сообщения не всплывали у тех, кто не заходил в базу месяц.ПараметрыСеанса, чтобы снизить нагрузку на СУБД.Систему взаимодействия. Это обеспечит минимальный отклик и отсутствие лишнего трафика.ПоказатьОповещениеПользователя(). Оно не блокирует работу интерфейса, в отличие от модальных окон, которые в современных версиях платформы (в режиме «Без модальности») требуют написания сложных обратных вызовов (описания оповещения).Мы проанализировали основные подходы к созданию системы разовых уведомлений. Выбор конкретного метода зависит от архитектуры вашей конфигурации и требований к производительности системы.