В процессе разработки учетных систем часто возникает ситуация: фоновое задание, HTTP-сервис или другой пользователь изменяет реквизиты документа, но у работающего в системе оператора на экране остаются устаревшие данные. Чтобы увидеть актуальную информацию, пользователю приходится вручную нажимать клавишу перечитывания данных.
Стандартное свойство формы списка Автообновление с небольшим интервалом (например, 5 секунд) решает вопрос актуализации, однако приводит к неприятным последствиям: в момент срабатывания таймера платформа повторно выполняет запрос динамического списка к СУБД, скроллинг замирает, а фокус ввода может сбиваться. Рассмотрим, почему так происходит, и разберем архитектурные решения, позволяющие обновлять данные только при возникновении реальных изменений.
Выясним причину, почему стандартные события интерфейса не срабатывают автоматически между разными пользователями. Клиент-серверная архитектура платформы «1С:Предприятие» традиционно использует модель pull-запросов: клиент обращается к серверу за данными, но сервер базы данных не может спонтанно отправить команду в открытую форму тонкого клиента.
Проанализируем методы, которые разработчики часто пытаются применить по ошибке:
ОбновитьОтображениеДанных() обновляет только визуальное представление уже загруженных в память клиента данных текущего сеанса и не перечитывает таблицы базы данных.Оповестить() и ОповеститьОбИзменении() работают строго в рамках локального клиентского приложения и не транслируются по сети в соседние клиентские сеансы.Элементы.Список.Обновить() сбрасывает кэш динамического списка целиком, заставляя СУБД заново строить выборку строк, что вызывает фризы интерфейса при частых вызовах.Рассмотрим наиболее современный и рекомендуемый платформенный механизм, позволяющий организовать доставку оповещений в реальном времени без постоянных тяжелых запросов к базе данных. Механизм Системы взаимодействия функционирует по push-модели на базе защищенного протокола WebSocket.
Разберем реализацию по шагам:
Посмотрим на пример отправки оповещения из серверного кода HTTP-сервиса:
// Серверный код (HTTP-сервис или регламентное задание)
Сообщение = СистемаВзаимодействия.СоздатьСообщение();
Сообщение.Обсуждение = ИдентификаторОбсужденияОповещений;
Сообщение.Текст = "ОбновлениеДокумента";
// Передаем ссылку на измененный объект через параметры данных
ДанныеСообщения = Новый Структура("Ссылка", ИзмененныйДокументСсылка);
Сообщение.Данные = Новый ХранилищеЗначения(ДанныеСообщения);
Сообщение.Записать();
Теперь рассмотрим, как обработать данное событие на клиенте в форме списка:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем обработчик сообщений обсуждения
СистемаВзаимодействия.ПодключитьОбработчикВходящихСообщений(
"ОбработатьВходящееСообщениеОбсуждения"
);
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьВходящееСообщениеОбсуждения(Сообщение)
Если Сообщение.Текст = "ОбновлениеДокумента" Тогда
СтруктураДанных = Сообщение.Данные.Получить();
Если СтруктураДанных <> Неопределено И СтруктураДанных.Свойство("Ссылка") Тогда
// Инвалидируем кэш платформы только для конкретной строки
ОповеститьОбИзменении(СтруктураДанных.Ссылка);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Главное достоинство этого подхода: метод ОповеститьОбИзменении() обновляет только одну конкретную запись, если у динамического списка указано свойство Основная таблица, не перегружая список целиком.
Если Система взаимодействия в рабочей базе не развернута или отключена, разберем альтернативную схему с легким опросом. Чтобы не перегружать СУБД пересчетом динамического списка каждые 5 секунд, выделим отдельный легкий регистр сведений — очередь событий.
Создадим непериодический регистр сведений ОчередьОбновленияСписков со следующими реквизитами:
ИдентификаторСобытия (тип Число, автоинкремент или временная метка в миллисекундах).СсылкаНаОбъект (тип ссылки на отслеживаемый документ).При записи данных в HTTP-сервисе делаем быструю запись одной строки в этот регистр. В форме документа подключаем обработчик ожидания с небольшим интервалом:
&НаКлиенте
Переменная ПоследнийНомерСобытия;
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПоследнийНомерСобытия = ПолучитьТекущийМаксимальныйНомерСобытияНаСервере();
ПодключитьОбработчикОжидания("ПроверитьНаличиеИзменений", 3);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьНаличиеИзменений()
ИзмененныеСсылки = ПолучитьИзмененныеСсылкиНаСервере(ПоследнийНомерСобытия);
Если ИзмененныеСсылки.Количество() > 0 Тогда
Для Каждого Ссылка Из ИзмененныеСсылки Цикл
ОповеститьОбИзменении(Ссылка);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Посмотрим на пример серверной функции проверки очереди:
&НаСервереБезКонтекста
Функция ПолучитьИзмененныеСсылкиНаСервере(ПоследнийНомер)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Очередь.ИдентификаторСобытия КАК Идентификатор,
| Очередь.СсылкаНаОбъект КАК Ссылка
|ИЗ
| РегистрСведений.ОчередьОбновленияСписков КАК Очередь
|ГДЕ
| Очередь.ИдентификаторСобытия > &ПоследнийНомер
|УПОРЯДОЧИТЬ ПО
| Очередь.ИдентификаторСобытия ВОЗР";
Запрос.УстановитьПараметр("ПоследнийНомер", ПоследнийНомер);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
МассивСсылок = Новый Массив;
Пока Выборка.Следующий() Цикл
МассивСсылок.Добавить(Выборка.Ссылка);
ПоследнийНомер = Выборка.Идентификатор;
КонецЦикла;
Возврат МассивСсылок;
КонецФункции
Данный серверный вызов выполняется по первичному ключу за доли миллисекунды, не блокирует пользовательский интерфейс и передает клиенту только те ссылки, которые реально требуют перерисовки.
Проанализируем современный механизм платформы — поддержку работы с внешними брокерами сообщений и серверами событий по протоколу WebSocket. Начиная с версии 8.3.27, в платформе представлен объект WebSocketКлиент.
Разберем архитектуру такого решения:
WebSocketКлиент.ОповеститьОбИзменении().Этот вариант исключает любые периодические обращения к серверу 1С и базе данных, обеспечивая мгновенную реакцию формы без микрозависаний.
Если все же используется периодическое обновление, обратим внимание на базовые настройки производительности самого динамического списка:
ОповеститьОбИзменении().Грамотное сочетание точечного обновления через ОповеститьОбИзменении() с механизмом оповещений через Систему взаимодействия или очередь событий полностью устраняет подвисания интерфейса и гарантирует отображение актуальных данных.