Как обновить форму списка документов при изменении данных в другой сессии?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Стандартное свойство формы списка Автообновление с небольшим интервалом (например, 5 секунд) решает вопрос актуализации, однако приводит к неприятным последствиям: в момент срабатывания таймера платформа повторно выполняет запрос динамического списка к СУБД, скроллинг замирает, а фокус ввода может сбиваться. Рассмотрим, почему так происходит, и разберем архитектурные решения, позволяющие обновлять данные только при возникновении реальных изменений.

Причины проблемы и ограничения платформы

Выясним причину, почему стандартные события интерфейса не срабатывают автоматически между разными пользователями. Клиент-серверная архитектура платформы «1С:Предприятие» традиционно использует модель pull-запросов: клиент обращается к серверу за данными, но сервер базы данных не может спонтанно отправить команду в открытую форму тонкого клиента.

Проанализируем методы, которые разработчики часто пытаются применить по ошибке:

  1. Метод ОбновитьОтображениеДанных() обновляет только визуальное представление уже загруженных в память клиента данных текущего сеанса и не перечитывает таблицы базы данных.
  2. Методы Оповестить() и ОповеститьОбИзменении() работают строго в рамках локального клиентского приложения и не транслируются по сети в соседние клиентские сеансы.
  3. Команда Элементы.Список.Обновить() сбрасывает кэш динамического списка целиком, заставляя СУБД заново строить выборку строк, что вызывает фризы интерфейса при частых вызовах.

Способ 1. Использование встроенной «Системы взаимодействия» (Push-уведомления)

Рассмотрим наиболее современный и рекомендуемый платформенный механизм, позволяющий организовать доставку оповещений в реальном времени без постоянных тяжелых запросов к базе данных. Механизм Системы взаимодействия функционирует по push-модели на базе защищенного протокола WebSocket.

Разберем реализацию по шагам:

  1. В коде HTTP-сервиса, фонового задания или обработчика проведения документа во внешнем сеансе отправляем системное сообщение через менеджер системы взаимодействия.
  2. В модуле управляемой формы списка подключаем обработчик входящих сообщений.
  3. При поступлении сигнала из другого сеанса вызываем точечное обновление нужной строки через глобальный контекст.

Посмотрим на пример отправки оповещения из серверного кода HTTP-сервиса:


// Серверный код (HTTP-сервис или регламентное задание)
Сообщение = СистемаВзаимодействия.СоздатьСообщение();
Сообщение.Обсуждение = ИдентификаторОбсужденияОповещений;
Сообщение.Текст = "ОбновлениеДокумента";

// Передаем ссылку на измененный объект через параметры данных
ДанныеСообщения = Новый Структура("Ссылка", ИзмененныйДокументСсылка);
Сообщение.Данные = Новый ХранилищеЗначения(ДанныеСообщения);

Сообщение.Записать();

Теперь рассмотрим, как обработать данное событие на клиенте в форме списка:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем обработчик сообщений обсуждения
    СистемаВзаимодействия.ПодключитьОбработчикВходящихСообщений(
        "ОбработатьВходящееСообщениеОбсуждения"
    );
КонецПроцедуры

&НаКлиенте
Процедура ОбработатьВходящееСообщениеОбсуждения(Сообщение)
    Если Сообщение.Текст = "ОбновлениеДокумента" Тогда
        СтруктураДанных = Сообщение.Данные.Получить();
        Если СтруктураДанных <> Неопределено И СтруктураДанных.Свойство("Ссылка") Тогда
            // Инвалидируем кэш платформы только для конкретной строки
            ОповеститьОбИзменении(СтруктураДанных.Ссылка);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Главное достоинство этого подхода: метод ОповеститьОбИзменении() обновляет только одну конкретную запись, если у динамического списка указано свойство Основная таблица, не перегружая список целиком.

Способ 2. Оптимизированный опрос очереди изменений (Lightweight Polling)

Если Система взаимодействия в рабочей базе не развернута или отключена, разберем альтернативную схему с легким опросом. Чтобы не перегружать СУБД пересчетом динамического списка каждые 5 секунд, выделим отдельный легкий регистр сведений — очередь событий.

Создадим непериодический регистр сведений ОчередьОбновленияСписков со следующими реквизитами:

  1. Измерение ИдентификаторСобытия (тип Число, автоинкремент или временная метка в миллисекундах).
  2. Ресурс СсылкаНаОбъект (тип ссылки на отслеживаемый документ).

При записи данных в HTTP-сервисе делаем быструю запись одной строки в этот регистр. В форме документа подключаем обработчик ожидания с небольшим интервалом:


&НаКлиенте
Переменная ПоследнийНомерСобытия;

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ПоследнийНомерСобытия = ПолучитьТекущийМаксимальныйНомерСобытияНаСервере();
    ПодключитьОбработчикОжидания("ПроверитьНаличиеИзменений", 3);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьНаличиеИзменений()
    ИзмененныеСсылки = ПолучитьИзмененныеСсылкиНаСервере(ПоследнийНомерСобытия);
    
    Если ИзмененныеСсылки.Количество() > 0 Тогда
        Для Каждого Ссылка Из ИзмененныеСсылки Цикл
            ОповеститьОбИзменении(Ссылка);
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Посмотрим на пример серверной функции проверки очереди:


&НаСервереБезКонтекста
Функция ПолучитьИзмененныеСсылкиНаСервере(ПоследнийНомер)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Очередь.ИдентификаторСобытия КАК Идентификатор,
        |   Очередь.СсылкаНаОбъект КАК Ссылка
        |ИЗ
        |   РегистрСведений.ОчередьОбновленияСписков КАК Очередь
        |ГДЕ
        |   Очередь.ИдентификаторСобытия > &ПоследнийНомер
        |УПОРЯДОЧИТЬ ПО
        |   Очередь.ИдентификаторСобытия ВОЗР";
    
    Запрос.УстановитьПараметр("ПоследнийНомер", ПоследнийНомер);
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    МассивСсылок = Новый Массив;
    Пока Выборка.Следующий() Цикл
        МассивСсылок.Добавить(Выборка.Ссылка);
        ПоследнийНомер = Выборка.Идентификатор;
    КонецЦикла;
    
    Возврат МассивСсылок;
КонецФункции

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

Способ 3. Использование встроенного протокола WebSocket

Проанализируем современный механизм платформы — поддержку работы с внешними брокерами сообщений и серверами событий по протоколу WebSocket. Начиная с версии 8.3.27, в платформе представлен объект WebSocketКлиент.

Разберем архитектуру такого решения:

  1. HTTP-сервис или внешний скрипт после модификации данных отправляет уведомление в брокер сообщений (например, RabbitMQ).
  2. Клиент 1С при открытии рабочего места держит открытое соединение с брокером через WebSocketКлиент.
  3. При получении текстового фрейма в обработчике события WebSocket-клиента платформа считывает идентификатор измененного объекта и передает его в ОповеститьОбИзменении().

Этот вариант исключает любые периодические обращения к серверу 1С и базе данных, обеспечивая мгновенную реакцию формы без микрозависаний.

Рекомендации по оптимизации динамического списка

Если все же используется периодическое обновление, обратим внимание на базовые настройки производительности самого динамического списка:

  1. Обязательно проверяем заполнение свойства Основная таблица. Если поле пустое, платформа не способна применять кэширование и точечное обновление строк через ОповеститьОбИзменении().
  2. Исключаем соединения с виртуальными таблицами итогов и срезов без жестко установленных параметров в запросе динамического списка.
  3. Убеждаемся, что поля, по которым настроена сортировка по умолчанию, входят в состав индексов СУБД.

Грамотное сочетание точечного обновления через ОповеститьОбИзменении() с механизмом оповещений через Систему взаимодействия или очередь событий полностью устраняет подвисания интерфейса и гарантирует отображение актуальных данных.

← На главную