Как дождаться завершения асинхронной отправки данных в 1С перед закрытием программы?

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

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

Разберем причины такого поведения платформы «1С:Предприятие 8.3» и рассмотрим правильные варианты реализации ожидания завершения отправки.

Почему отправка прерывается при вызове ЗавершитьРаботуСистемы?

Проанализируем типовой фрагмент кода, приводящий к ошибке:


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

ЗавершитьРаботуСистемы(Ложь);

Причина сбоя заключается в особенностях работы асинхронных клиентских методов и криптографических операций:

  1. Асинхронная природа вызовов: методы подсистемы «1С-Отчетность» и документооборота с контролирующими органами (такие как ПолучитьКонтекстЭДО и ОтправкаЗапросаНаИнформационноеОбслуживание) являются неблокирующими. Они инициируют процесс в фоновом потоке или через системные интерфейсы криптопровайдера и сразу же передают управление следующей строке кода.
  2. Неразрывная цепочка вызовов: метод отправки не должен вызываться сразу же следом за получением контекста — он должен запускаться внутри процедуры обратного вызова (в процедуре ПриОткрытииЗавершение), когда контекст ЭДО уже гарантированно сформирован.
  3. Прерывание очереди сообщений: вызов ЗавершитьРаботуСистемы(Ложь) исполняется синхронно в основном потоке клиента, мгновенно останавливая выполнение всех запланированных асинхронных операций и закрывая окна взаимодействия с криптографией.

Способ 1. Завершение сеанса внутри обработчика оповещения (Рекомендуемый)

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

Разберем по шагам правильную организацию цепочки вызовов:

  1. Создаем экспортную процедуру для завершения контекста ЭДО, из которой инициируем отправку.
  2. Создаем экспортную процедуру завершения отправки, в которой проверяем результат и только затем вызываем завершение работы сеанса.

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


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

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

&НаКлиенте
Процедура ПослеЗавершенияОтправки(Результат, ДополнительныеПараметры) Экспорт
    
    // В этот момент отправка, подписание и передача пакета полностью завершены
    // При необходимости можно зафиксировать лог выполнения
    
    ЗавершитьРаботуСистемы(Ложь);
    
КонецПроцедуры

Способ 2. Отслеживание состояния через обработчик ожидания

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

Рассмотрим порядок реализации:

  1. Запускаем процесс отправки документа.
  2. Подключаем циклический клиентский обработчик ожидания с интервалом в несколько секунд.
  3. В теле обработчика серверным вызовом опрашиваем регистры сведений подсистемы документооборота или реквизиты состояния документа.
  4. При получении статуса «Отправлен» (или при возникновении критической ошибки/таймаута) отключаем обработчик ожидания с помощью метода ОтключитьОбработчикОжидания и завершаем сеанс.

Посмотрим на пример кода:


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

&НаКлиенте
Процедура ПроверитьСтатусОтправки()
    
    СостояниеОтправки = ПроверитьСтатусНаСервере(Объект.СсылкаНаСверку);
    
    Если СостояниеОтправки = "Отправлен" Или СостояниеОтправки = "Ошибка" Тогда
        ОтключитьОбработчикОжидания("ПроверитьСтатусОтправки");
        ЗавершитьРаботуСистемы(Ложь);
    КонецЕсли;
    
КонецПроцедуры

Возможность выполнения отправки в фоновом задании на сервере

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

Серверное подписание возможно, только если:

  1. Криптопровайдер (СКЗИ) установлен непосредственно на сервере «1С:Предприятия».
  2. Сертификаты ЭП и закрытые ключи установлены в хранилище учетной записи операционной системы, под которой запущена служба сервера 1С.
  3. В настройках электронной подписи конфигурации включена опция выполнения цифровой подписи на сервере.

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

← На главную