Как вывести сообщение или уведомление пользователю во время выполнения регламентного задания?

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

При разработке регламентных заданий в среде 1С:Предприятие 8.3 начинающие специалисты часто сталкиваются с проблемой: методы Сообщить() или СообщениеПользователю, прекрасно работающие в обычных формах или обработках, внутри регламентного задания не выводят никаких окон на экран пользователя. Разберем ситуацию: регламентное задание выполняется на сервере в отдельном, фоновом сеансе. У этого сеанса нет «лица» — графического интерфейса, поэтому все отправленные сообщения просто записываются в лог этого фонового сеанса и исчезают после его завершения. Наша задача — передать информацию из этого «невидимого» серверного процесса в активный сеанс конкретного пользователя.

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

Метод 1: Использование регистра сведений и обработчика ожидания

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

Шаг 1. Создание регистра. Создадим непериодический регистр сведений, например, ОчередьУведомлений. В качестве измерений добавим Пользователь (тип СправочникСсылка.Пользователи), а в ресурсы — ТекстСообщения и ДатаСобытия.

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


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

Шаг 3. Получение на клиенте. В модуле управляемого приложения (или в основной форме) настроим периодическую проверку этого регистра с помощью метода ПодключитьОбработчикОжидания.


// В модуле управляемого приложения
Процедура ПриНачалеРаботыСистемы()
    ПодключитьОбработчикОжидания("ПроверитьНовыеУведомления", 60); // Проверка раз в минуту
КонецПроцедуры

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

Метод 2: Использование подсистемы «Длительные операции» (БСП)

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

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

Рассмотрим, как программно создать напоминание в БСП:


// Пример создания напоминания через программный интерфейс БСП
ПараметрыНапоминания = Новый Структура;
ПараметрыНапоминания.Вставить("Пользователь", ПользовательСсылка);
ПараметрыНапоминания.Вставить("ВремяНапоминания", ТекущаяДата());
ПараметрыНапоминания.Вставить("Описание", "Проверьте входящие документы!");
ПараметрыНапоминания.Вставить("Источник", ДокументСсылка); // Ссылка на объект

НапоминанияПользователя.СоздатьНапоминание(ПараметрыНапоминания);

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

Метод 3: Система взаимодействия (Push-уведомления)

Выясним, какой способ является самым современным. Система взаимодействия позволяет серверу напрямую «толкнуть» сообщение клиенту. Это работает мгновенно и не нагружает базу данных постоянными опросами регистров.

Разберем пример кода для отправки сообщения конкретному пользователю:


// Код выполняется в регламентном задании на сервере
ПользовательОбъект = Пользователи.ИнформационнаяБазаПользователь(НужныйПользователь);
ИдентификаторПользователя = СистемаВзаимодействия.ИдентификаторПользователя(ПользовательОбъект.УникальныйИдентификатор);

// Ищем или создаем обсуждение между сервером (системой) и пользователем
Отбор = Новый Структура;
МассивУчастников = Новый Массив;
МассивУчастников.Добавить(ИдентификаторПользователя);
Отбор.Вставить("Участники", МассивУчастников);

Обсуждения = СистемаВзаимодействия.ПолучитьОбсуждения(Отбор);
Если Обсуждения.Количество() > 0 Тогда
    Обсуждение = Обсуждения[0];
Иначе
    Обсуждение = СистемаВзаимодействия.СоздатьОбсуждение();
    Обсуждение.Участники.Добавить(ИдентификаторПользователя);
    Обсуждение.Записать();
КонецЕсли;

НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
НовоеСообщение.Текст = "Регламентное задание: обнаружены ошибки в данных!";
НовоеСообщение.Записать();

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

Почему ПолучитьСообщенияПользователю не помогает автору вопроса?

Проанализируем ошибку в первом сообщении темы. Автор пытается вызвать РЗ.ПолучитьСообщенияПользователю() внутри самого регламентного задания. Это логическая ошибка по двум причинам:

  1. Контекст: Метод ПолучитьСообщенияПользователю предназначен для того, чтобы внешний сеанс (клиентский) мог прочитать сообщения, которые накопились внутри фонового сеанса. Вызывать его внутри самого себя бессмысленно — он вернет те сообщения, которые вы только что создали через Сообщить(), но они всё равно останутся внутри этого фонового сеанса.
  2. Объект задания: Регламентное задание и Фоновое задание в программной модели 1С — это разные объекты. У сообщения есть связь с идентификатором фонового задания. Чтобы клиент увидел сообщение, он должен найти ФоновоеЗадание по ID и вызвать этот метод у него. Но регламентные задания запускаются планировщиком, и клиентский сеанс «не знает» ID конкретного запуска, если только мы не сохраним его специально.

Рекомендации по выбору решения

Подведем итог и выберем оптимальный путь для вашей ситуации:

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

← На главную