Как определить, выполняет ли приложение 1С фоновые или асинхронные процессы?

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

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

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

Разграничение понятий: Фоновые задания vs Асинхронные вызовы

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

  1. Фоновые задания (серверные): Это процессы, запускаемые на стороне сервера 1С. Они управляются менеджером фоновых заданий и не зависят от жизни клиентского сеанса.
  2. Асинхронные вызовы (клиентские): Это современные методы (использующие ключевые слова Асинх, Ждать или старые обработчики оповещений), которые выполняются в контексте клиентского приложения. Если закрыть 1cv8c.exe, эти процессы мгновенно прекратятся.

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

Мониторинг серверных фоновых заданий

Если ваша задача выполняется на сервере, мы можем легко получить список активных процессов. Рассмотрим, как это сделать программно. Мы можем использовать метод ПолучитьФоновыеЗадания() с фильтром по состоянию Активно.

Разберем пример кода, который проверяет наличие работающих заданий для конкретного пользователя или по определенному наименованию:


Отбор = Новый Структура;
Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно);
Отбор.Вставить("Наименование", "ВыгрузкаНаКассы");

СписокЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор);

Если СписокЗаданий.Количество() > 0 Тогда
    Сообщить("Выгрузка еще продолжается...");
Иначе
    Сообщить("Все задания завершены.");
КонецЕсли;

Этот метод надежен для серверных процессов, но совершенно бесполезен для контроля асинхронных функций, запущенных в тонком клиенте.

Проблема "счетчика" в асинхронном коде и ее решение

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

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

Рассмотрим пример правильной организации цикла выгрузки:


&НаКлиенте
Асинх Процедура ВыполнитьВыгрузкуНаВсеКассыАсинх()
    
    МассивОбещаний = Новый Массив;
    
    Для Каждого Касса Из СписокКасс Цикл
        // Каждая выгрузка возвращает Обещание (Promise)
        МассивОбещаний.Добавить(ВыгрузитьНаОднуКассуАсинх(Касса));
    КонецЦикла;
    
    Попытка
        // Ждем завершения ВСЕХ процессов
        Ждать Обещание.Все(МассивОбещаний);
        ЗавершитьРаботуСистемы(Ложь);
    Исключение
        ЗаписатьЛогОшибки(ОписаниеОшибки());
        // Даже при ошибке одной кассы, мы должны решить: 
        // закрывать робота или ждать исправления
        ЗавершитьРаботуСистемы(Ложь);
    КонецПопытки;
    
КонецПроцедуры

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

Контроль через состояние внешних компонент

При работе с Frontol или другими кассовыми системами часто используются внешние компоненты (Add-in). Иногда асинхронность 1С накладывается на внутренние задержки драйвера. Выясним, как понять, что драйвер еще занят.

Многие компоненты имеют свойство State или IsBusy. Если вы используете асинхронные методы самой компоненты, обязательно проверяйте статус завершения в обработчике ВнешнееСобытие. Пока не получено событие от последней кассы, закрывать приложение нельзя.

Альтернативный метод: Мониторинг через технологический журнал

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

Для этого настройте сбор событий CALL (вызовы сервера) и SCALL (серверные вызовы). Пока в файл лога пишутся новые строки для процесса вашего робота, значит, приложение активно взаимодействует с базой данных и выгрузка продолжается. Как только активность в логах затихает на определенный период (например, 1-2 минуты), можно сделать вывод, что приложение простаивает и его можно принудительно завершить через Taskkill или средствами самой ОС.

Практические рекомендации для стабильной работы робота

Подведем итог и составим пошаговый план для реализации надежного механизма:

  1. Оберните все асинхронные блоки в Попытка...КонецПопытки: Это гарантирует, что даже при ошибке связи с кассой выполнение кода дойдет до точки контроля.
  2. Используйте механизмы платформы 8.3.18+: Если версия позволяет, переходите на Асинх/Ждать и Обещание.Все(). Это избавляет от проблем с глобальными переменными-счетчиками.
  3. Логирование в БД: Перед стартом задачи записывайте в специальный регистр сведений запись об активности ("Касса №1 — в процессе"). По завершении — удаляйте. Робот перед выходом должен проверить: если регистр пуст — можно закрываться.
  4. Таймаут безопасности: Всегда устанавливайте максимальное время жизни робота. Если выгрузка обычно идет 5 минут, настройте принудительное завершение через 20 минут, чтобы "зависший" сеанс не блокировал последующие запуски.

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

← На главную