В процессе разработки сложных механизмов в 1С, когда требуется запустить несколько параллельных процессов, программисты часто сталкиваются с проблемой: как эффективно собирать информацию о ходе выполнения (логи) и отображать её пользователю в режиме реального времени. В этой статье мы подробно разберем, как правильно организовать логирование, почему работа с файлами на сервере может быть опасна и какие стандартные механизмы платформы и БСП (Библиотеки стандартных подсистем) лучше всего подходят для этой задачи.
Рассмотрим ситуацию, когда мы пытаемся записывать лог в обычный текстовый файл во временной директории сервера. На первый взгляд это кажется логичным, но здесь кроется серьезная архитектурная ловушка. Разберем по шагам, почему это может не работать.
В системе 1С:Предприятие 8.3 при работе в кластере серверов существует понятие Session Affinity (привязка сеанса). Основной сеанс пользователя обычно привязан к конкретному рабочему процессу (rphost) на конкретном сервере. Однако фоновые задания, которые вы запускаете, могут быть распределены кластером на любой другой сервер, где разрешено выполнение фоновых заданий.
Проанализируем риски: если ваша основная форма создала временный файл на Сервере №1, а фоновое задание запустилось на Сервере №2, оно физически не увидит этот файл. Попытка дозаписи приведет к ошибке или созданию нового пустого файла на другом сервере. Таким образом, использование локальных путей типа КаталогВременныхФайлов() для межоперационного обмена данными в многосерверном кластере недопустимо.
Решение: Если вы все же решили использовать файлы, необходимо использовать общую сетевую папку (UNC-путь), доступ к которой имеют учетные записи, под которыми запущены службы 1С на всех серверах кластера. Но, как мы увидим далее, есть более изящные способы.
Самый простой и быстрый способ передать информацию из фонового задания на клиента — это использование объекта СообщениеПользователю. Рассмотрим, как это работает на практике. Внутри серверного кода фонового задания мы просто выводим информацию:
// В коде фонового задания
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Обработано объектов: " + Строка(Количество);
Сообщение.Сообщить();
Теперь выясним, как получить эти данные. На стороне клиента мы подключаем обработчик ожидания, который вызывает серверную процедуру. В этой процедуре мы используем метод ПолучитьСообщенияПользователю() для объекта фонового задания.
Разберем важные нюансы этого метода:
rphost и замедлению передачи данных из-за сериализации огромных массивов.Если в вашей конфигурации используется БСП, то наиболее правильным и современным способом будет использование модуля ДлительныеОперации. Рассмотрим этот подход подробнее, так как он инкапсулирует в себе все сложности взаимодействия с фоновыми заданиями.
Для передачи прогресса и лога используем метод ДлительныеОперации.СообщитьПрогресс(). Этот метод позволяет передавать не просто текст, а структуру данных, что гораздо удобнее для парсинга на клиенте.
// Внутри фонового задания
ТекстЛога = "Запись успешно создана";
ПроцентВыполнения = 45;
СтруктураДопПараметров = Новый Структура("Важность, Сообщение", "Инфо", ТекстЛога);
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, СтруктураДопПараметров);
На стороне клиента, в обработчике ожидания, мы вызываем функцию ДлительныеОперации.ПрочитатьПрогресс(). Она вернет нам массив структур, которые были переданы из фонового задания с момента последней проверки. Это позволяет реализовать плавный индикатор прогресса и детальный лог выполнения без лишней нагрузки на систему.
Рассмотрим ситуацию, когда лог очень большой или его необходимо сохранить для последующего анализа даже после завершения работы пользователя. В этом случае лучшим выбором будет использование Регистра Сведений (РС).
Однако при параллельной работе 10 фоновых заданий, пишущих в один регистр, мы можем столкнуться с проблемой блокировок. Проанализируем, как этого избежать:
UUID) конкретного запуска или задания. Это позволит развести потоки записи по разным физическим записям базы данных.Пример записи в лог через регистр:
МенеджерЗаписи = РегистрыСведений.ЛогПроцессов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИдентификаторЗапуска = ПараметрыЗапуска.ID;
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.ТекстСообщения = "Шаг 1 завершен";
МенеджерЗаписи.Записать(Истина);
Еще один способ — использование Временного хранилища. Вы можете передать в фоновое задание АдресХранилища, в который оно будет помещать результаты своей работы. Но помните важную особенность: данные, помещенные во временное хранилище из фонового задания, становятся доступны основному сеансу только после того, как задание полностью завершится, либо если используются специальные механизмы передачи идентификаторов, что усложняет реализацию.
Подведем итог нашему анализу и выберем оптимальную стратегию:
ДлительныеОперации.СообщитьПрогресс() и клиентский обработчик ожидания.ЗаписьЖурналаРегистрации(). Помните, что чтение из Журнала регистрации в реальном времени — очень тяжелая операция.Используя эти подходы, вы сможете создать надежную и производительную систему мониторинга длительных операций в ваших решениях на платформе 1С.