Как автоматически обновить открытые списки справочников в 1С при изменении данных фоновым заданием?

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

При разработке интеграций в среде 1С часто возникает стандартная архитектурная проблема: регламентное или фоновое задание успешно затягивает новые данные из внешней базы (например, MS Access, MS SQL или веб-сервиса), записывает их в базу данных 1С, но пользователи, у которых в этот момент открыты списки справочников или документов, не видят изменений до тех пор, пока не нажмут клавишу F5 или кнопку «Обновить».

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

Почему стандартный метод ОповеститьОбИзменении() не работает с сервера напрямую?

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

Однако этот метод является строго клиентским. Попытка вызвать его в общем модуле, который выполняется на сервере под управлением регламентного задания, приведет к ошибке компиляции или выполнения: «Процедура или функция с указанным именем не определена». Серверный код фонового задания выполняется изолированно от клиентских сеансов. Чтобы обойти это ограничение, нам придется использовать специальные архитектурные подходы.

---

Решение №1: Использование встроенного механизма «АвтоОбновление» динамического списка

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

У каждого динамического списка в управляемой форме (в свойствах таблицы на форме) есть два важных параметра:

  1. АвтоОбновление — булево свойство, включающее периодический опрос базы данных платформой.
  2. ПериодАвтоОбновления — частота опроса в секундах (минимальное значение — 10 секунд).

Если мы установим свойство АвтоОбновление в значение Истина и укажем период, например, 60 секунд, платформа сама, без написания какого-либо программного кода, будет каждые 60 секунд отправлять неявный запрос к базе данных и обновлять содержимое списка на экране пользователя.

Плюсы метода:

  1. Предельная простота настройки (выполняется визуально в конфигураторе).
  2. Работает «из коробки» на любых версиях платформы 1С:Предприятие 8.

Минусы метода:

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

---

Решение №2: Классический паттерн «Регистр сведений + Обработчик ожидания»

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

Разберем по шагам алгоритм реализации этого метода:

Шаг 1. Создание вспомогательного регистра сведений

Создадим в конфигураторе простой регистр сведений (например, ИсторияОбновленияДанных) со следующей структурой:

Шаг 2. Фиксация изменений на сервере

В коде общего модуля, который выполняется регламентным заданием, в самом конце процедуры успешного импорта данных добавим запись в наш регистр сведений:


Процедура ЗафиксироватьОбновлениеДанныхНаСервере() Экспорт
    
    МенеджерЗаписи = РегистрыСведений.ИсторияОбновленияДанных.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.ИмяСправочника = "Номенклатура";
    МенеджерЗаписи.ДатаПоследнегоОбновления = ТекущаяДатаСеанса();
    МенеджерЗаписи.Записать(Истина);
    
КонецПроцедуры

Шаг 3. Настройка формы списка справочника

Теперь перейдем в форму списка нашего справочника (например, «Номенклатура»). В модуле формы объявим переменную для хранения локального времени последнего обновления и подключим обработчик ожидания при создании формы:


&НаКлиенте
Перем ЛокальнаяДатаОбновления;

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Получаем начальную дату при открытии формы
    ЛокальнаяДатаОбновления = ПолучитьДатуОбновленияССервера();
    
КонецПроцедуры

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

Шаг 4. Написание логики проверки и обновления

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


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

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

Использование директивы &НаСервереБезКонтекста критически важно: такой вызов выполняется сервером мгновенно, не передает состояние всей формы (данные, реквизиты) туда и обратно, благодаря чему нагрузка на сеть и процессор сводится к абсолютному минимуму.

---

Решение №3: Современный Push-метод через «Систему взаимодействия» (Платформа 8.3.10+)

Если вы работаете на современной платформе (версии 8.3.10 и выше), наиболее технологичным решением является использование механизма Системы взаимодействия. Это встроенный инструмент 1С, позволяющий организовывать обмен сообщениями в реальном времени между сервером и клиентами (через веб-сокеты) по технологии Push.

При этом подходе клиенту вообще не нужно постоянно обращаться к серверу с проверками — сервер сам «толкнет» клиентские сеансы при необходимости.

Рассмотрим, как настроить этот процесс программно:

Шаг 1. Отправка Push-уведомления с сервера (в фоновом задании)

В регламентном задании после окончания обработки импорта пишем код отправки сообщения в специальный неинтерактивный канал (обсуждение):


Процедура ОтправитьСигналОбновленияКлиентам() Экспорт
    
    Если НЕ СистемаВзаимодействия.Поддерживается() Тогда
        Возврат;
    КонецЕсли;
    
    // В фоновом задании важно установить системного пользователя для работы с СВ
    СистемаВзаимодействия.УстановитьТекущегоПользователя(ПользователиИнформационнойБазы.НайтиПоИмени("Администратор"));
    
    // Ищем или создаем наше системное обсуждение
    КлючОбсуждения = "ОбновлениеНоменклатурыСинхронизация";
    ПараметрыОтбора = Новый Структура("Ключ", КлючОбсуждения);
    СписокОбсуждений = СистемаВзаимодействия.ПолучитьОбсуждения(ПараметрыОтбора);
    
    Если СписокОбсуждений.Количество() > 0 Тогда
        Обсуждение = СписокОбсуждений[0];
    Иначе
        Обсуждение = СистемаВзаимодействия.СоздатьОбсуждение();
        Обсуждение.Ключ = КлючОбсуждения;
        Обсуждение.Наименование = "Системные уведомления о синхронизации";
        Обсуждение.Записать();
    КонецЕсли;
    
    // Отправляем неинтерактивное сообщение-сигнал
    НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
    НовоеСообщение.Текст = "REFRESH_NOMENCLATURE";
    НовоеСообщение.Записать();
    
КонецПроцедуры

Шаг 2. Перехват сообщения на клиенте

В модуле управляемого приложения (или непосредственно в форме списка) подписываемся на получение сообщений этого обсуждения:


&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
    
    ПодключитьОбработчикСообщений();
    
КонецПроцедуры

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

&НаКлиенте
Процедура ПолученоНовоеСообщениеСВ(Сообщение, ДополнительныеПараметры) Экспорт
    
    Если Сообщение.Текст = "REFRESH_NOMENCLATURE" Тогда
        // Срабатывает мгновенное обновление на клиенте без циклического опроса сервера!
        ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура"));
    КонецЕсли;
    
КонецПроцедуры

Этот метод является самым изящным и производительным, так как полностью исключает лишнюю нагрузку на сервер БД.

---

Решение №4: Использование «Менеджера уведомлений клиента» (Платформа 8.3.26+)

В самых последних релизах платформы (начиная с версии 8.3.26) разработчики 1С представили долгожданный инструмент — МенеджерУведомленийКлиента. Этот механизм позволяет серверу отправлять сигналы напрямую в открытые сеансы без необходимости предварительной интеграции и настройки Системы взаимодействия.

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

---

Важный нюанс: Борьба с конфликтами изменения данных

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

Если пользователь попытается сохранить свою форму, платформа выдаст ошибку: «Данные были изменены или удалены другим пользователем». Это происходит из-за несовпадения версии объекта в памяти формы и в базе данных.

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

  1. Разделение прав (Мастер-система): Если 1С используется исключительно для отчетов и просмотра, а все изменения вносятся только во внешней базе данных, лучшим решением будет жестко заблокировать редактирование справочника пользователями в 1С. Установите у форм свойство ТолькоПросмотр = Истина или ограничьте права на уровне ролей (разрешить только Чтение и Просмотр).
  2. Программное перечитывание (метод Прочитать()): Если пользователям все же разрешено редактирование, вы можете при получении сигнала об обновлении программно проверять свойство формы Модифицированность:
    • Если Модифицированность = Ложь (пользователь ничего не менял на форме), мы можем безопасно вызвать метод ЭтаФорма.Прочитать(), чтобы обновить данные на актуальные из БД.
    • Если Модифицированность = Истина, трогать форму нельзя. Можно деликатно предупредить пользователя всплывающим сообщением о том, что данные этого элемента были обновлены внешней системой.

Мы подробно разобрали основные методы автоматического обновления открытых списков справочников в 1С. Выбирайте наиболее подходящий под ваши технические условия вариант: простое автообновление для небольших баз, паттерн с регистром сведений для надежной работы без перегрузки СУБД или современные Push-технологии платформы для интерактивных систем с высокой нагрузкой.

← На главную