Рассмотрим достаточно частую, но при этом нетривиальную задачу: нам необходимо конвертировать файлы (например, документы MS Office в PDF с помощью PDFCreator), но серверная часть платформы 1С развернута на ОС Linux (в связке Debian + PostgreSQL). В такой инфраструктуре сервер не имеет доступа к Windows-приложениям и специфичным COM-объектам. Из-за этого мы не можем использовать стандартные фоновые задания на сервере. Вся нагрузка по конвертации неизбежно ложится на клиентскую машину под управлением Windows. Проанализируем ситуацию и выясним, как выполнить эту длительную операцию в фоне, чтобы интерфейс пользователя не блокировался.
Прежде чем перейти к решениям, разберем архитектурные ограничения платформы 1С. Клиентское приложение 1С является строго однопоточным. Это означает, что любой тяжелый код, написанный на встроенном языке (например, инициализация COM-объектов MS Word или Excel, открытие файлов, перебор строк), при запуске на клиенте неизбежно заблокирует пользовательский интерфейс. Программа будет казаться зависшей до тех пор, пока выполнение процедуры не завершится.
Механизм ФоновыеЗадания, предоставляемый платформой, выполняется исключительно на стороне сервера кластера (или в отдельном невидимом потоке, если база файловая). Вызвать фоновое задание, которое исполнилось бы в контексте клиента, невозможно.
Также посмотрим на современные асинхронные методы платформы (вызовы через Асинх/Ждать или использование ОписаниеОповещения). Они предназначены для неблокирующего вызова диалогов операционной системы, работы с файловой системой или вызова внешних ресурсов, но они не умеют распараллеливать произвольный алгоритм, написанный на встроенном языке. Использование подсистемы ДлительныеОперации из БСП (Библиотеки стандартных подсистем) тоже не решит проблему: эта подсистема умеет показывать красивые индикаторы загрузки на клиенте, но сам исполняемый код все равно отправляет на сервер.
Поскольку клиент 1С не может создать дополнительный поток сам в себе, давайте делегируем эту задачу операционной системе. Мы можем вынести логику работы с MS Office и PDFCreator в отдельный исполняемый скрипт (например, файл .vbs, .js или .ps1).
Чтобы запуск этого скрипта из 1С не остановил основной поток, воспользуемся COM-объектом WScript.Shell. Рассмотрим метод Run этого объекта. Он принимает три параметра, где третий параметр bWaitOnReturn отвечает за то, должна ли программа дождаться завершения скрипта.
Разберем по шагам, как это выглядит в коде:
Оболочка = Новый COMОбъект("WScript.Shell");
ПутьКСкрипту = "C:\Scripts\ConvertDocToPdf.vbs";
// Передаем False третьим параметром, чтобы не ждать завершения
Оболочка.Run(ПутьКСкрипту, 0, Ложь);
При таком вызове управление моментально вернется пользователю в интерфейс 1С. Внешний скрипт в это время будет "дергать" MS Office, конвертируя файл в отдельном процессе операционной системы.
Отлично, мы запустили процесс в фоне. Но как конфигурации 1С узнать, что скрипт успешно завершил работу, и где забрать готовый PDF-файл? Рассмотрим два эффективных подхода.
ПодключитьОбработчикОжидания. Мы поручаем платформе, например, каждую секунду запускать легкую клиентскую процедуру, которая будет проверять наличие итогового файла или специального файла-флага в каталоге.
&НаКлиенте
Процедура НачатьКонвертацию()
// Запуск скрипта WScript.Shell...
ПодключитьОбработчикОжидания("ПроверитьГотовностьФайла", 2);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьГотовностьФайла()
ФайлРезультата = Новый Файл("C:\Temp\Result.pdf");
Если ФайлРезультата.Существует() Тогда
ОтключитьОбработчикОжидания("ПроверитьГотовностьФайла");
ПоказатьОповещениеПользователя("Успешно", , "Файл сконвертирован!");
КонецЕсли;
КонецПроцедуры
Если решение со скриптами кажется вам недостаточно надежным или сложным в развертывании (скрипты могут блокироваться антивирусами), рассмотрим более профессиональную альтернативу. Технология создания Внешних компонент (ВК) идеально подходит для таких задач.
На языках C# или C++ разрабатывается небольшая внешняя компонента (используя технологию Native API или COM). Эта компонента подключается прямо к клиенту 1С. При вызове метода, отвечающего за конвертацию, внутри компоненты создается новый рабочий поток операционной системы (используется классический мультитрединг). Управление немедленно возвращается в встроенный язык 1С.
Когда фоновый поток в компоненте заканчивает работу с MS Office, компонента генерирует внешнее событие. Это событие перехватывается в модуле формы 1С с помощью стандартного обработчика ОбработкаВнешнегоСобытия. Это самое изящное и правильное архитектурное решение: оно не требует сторонних серверов, не засоряет систему скриптами и абсолютно не блокирует пользовательский интерфейс.
В качестве "экстренной" меры разработчики иногда прибегают к запуску еще одного клиентского сеанса 1С. Суть метода заключается в том, что основной сеанс через командную строку запускает скрытый клиентский сеанс, передавая ему параметры запуска через ключ командной строки. Скрытый сеанс при старте считывает параметры (например, путь к файлу), синхронно выполняет конвертацию через COM-объекты (при этом зависает только он сам, будучи невидимым для пользователя), и по окончании записывает результат в базу или файл.
Основной сеанс отслеживает завершение точно так же — через ПодключитьОбработчикОжидания. У этого метода есть существенный минус: запуск нового сеанса 1С — ресурсоемкая операция. Она требует дополнительных лицензий 1С (если не используется программное мультиплексирование на одном ПК) и отнимает много оперативной памяти. Мы рекомендуем использовать этот подход только в том случае, если по каким-то причинам недоступны внешние скрипты и компоненты.
Подведем итог: из-за однопоточности клиента 1С прямая фоновая работа с COM-объектами невозможна. Выход — вынесение тяжелых операций за рамки процесса 1С. Наилучшими решениями являются написание собственной внешней компоненты с асинхронными событиями или использование внешних скриптов с неблокирующим запуском и последующим опросом результата по таймеру.