Как устранить ошибку Аварийно завершился процесс фонового задания при многопоточной записи PDF в 1С

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

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

Суть проблемы и анализ исходного кода

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


КоличествоПотоковПечати = 4;
МассивЗаданий = Новый Массив;

Для каждого ЭлGTIN Из ТЗ Цикл
    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(ЭлGTIN.GTIN);
    
    Задание = ФоновыеЗадания.Выполнить("ВзаимодействиеСервер.СформироватьЭтикеткиИЗаписатьВФайл", МассивПараметров);
    МассивЗаданий.Добавить(Задание);
    
    Если МассивЗаданий.Количество() >= КоличествоПотоковПечати Тогда  
        Попытка
            ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий);
        Исключение
            // Обработка ошибки
        КонецПопытки;
        МассивЗаданий.Очистить();
    КонецЕсли;
КонецЦикла;

Внутри процедуры СформироватьЭтикеткиИЗаписатьВФайл выполняется стандартный метод Записать() объекта ТабличныйДокумент. Проблема заключается в том, что при одновременном обращении нескольких потоков к библиотекам экспорта PDF процесс rphost может завершиться с ошибкой Access Violation. Это приводит к падению всего рабочего процесса, обрыву всех активных соединений и появлению "битых" файлов размером в несколько байт.

Причины возникновения ошибки

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

  1. Непотокобезопасность графической подсистемы: В версии 8.3.16 внутренние механизмы платформы, отвечающие за рендеринг шрифтов и формирование PDF-структуры, не всегда корректно изолированы. При параллельной работе возникают конфликты доступа к разделяемым ресурсам в памяти.
  2. Конфликты временных файлов: Метод Записать() при экспорте в PDF часто создает промежуточные данные во временной директории профиля пользователя ОС. При массовом запуске потоков может возникнуть коллизия имен или блокировка доступа к папке Temp.
  3. Лимиты памяти rphost: Генерация PDF — крайне ресурсоемкая задача. Если в настройках кластера 1С установлены жесткие ограничения на объем памяти на один процесс, одновременная работа 4 и более потоков с тяжелыми табличными документами может мгновенно превысить лимит, что спровоцирует принудительное завершение процесса кластером.
  4. Особенности ОС Linux: Если сервер 1С работает под управлением Linux, проблема может усугубляться отсутствием необходимых библиотек (например, libfontconfig1) или некорректным доступом к кэшу шрифтов при многопоточной инициализации.

Решение 1: Использование промежуточного потока в памяти

Одним из эффективных способов обхода прямой записи на диск является использование объекта ПотокВПамяти. Это позволяет изолировать процесс формирования данных от процесса записи файла в файловую систему. Разберем этот метод подробнее:


Процедура СформироватьЭтикеткиИЗаписатьВФайл(GTIN) Экспорт
    // Формируем табличный документ
    Данные = ПечатьЭтикеток.ПолучитьЭтикетки_V2(ПараметрыФормирования);
    
    // Вместо прямой записи на диск используем поток в памяти
    Птк = Новый ПотокВПамяти;
    Данные.ТД.Записать(Птк, ТипФайлаТабличногоДокумента.PDF);
    
    // Получаем двоичные данные из потока
    ДД = Птк.ЗакрытьИПолучитьДвоичныеДанные();
    
    // Записываем двоичные данные в файл
    ДД.Записать(ПутьСохранения + "\" + ИмяФайла);
КонецПроцедуры

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

Решение 2: Оптимизация управления очередью заданий

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


КоличествоПотоков = 4;
АктивныеЗадания = Новый Массив;

Для каждого СтрокаТЗ Из ТЗ Цикл
    // Ждем, пока освободится место в пуле потоков
    Пока АктивныеЗадания.Количество() >= КоличествоПотоков Цикл
        // Проверяем статус заданий
        ИндексыДляУдаления = Новый Массив;
        Для Номер = 0 По АктивныеЗадания.Количество() - 1 Цикл
            Если АктивныеЗадания[Номер].Состояние <> СостояниеФоновогоЗадания.Активно Тогда
                ИндексыДляУдаления.Добавить(Номер);
            КонецЕсли;
        КонецЦикла;
        
        // Очищаем завершенные
        Для каждого Индекс Из ИндексыДляУдаления Цикл
            АктивныеЗадания.Удалить(Индекс);
        КонецЦикла;
        
        Если АктивныеЗадания.Количество() >= КоличествоПотоков Тогда
            Приостановить(1); // Небольшая пауза, чтобы не нагружать процессор проверками
        КонецЕсли;
    КонецЦикла;
    
    // Запуск нового задания
    Параметры = Новый Массив;
    Параметры.Добавить(СтрокаТЗ.GTIN);
    НовоеЗадание = ФоновыеЗадания.Выполнить("ВзаимодействиеСервер.СформироватьЭтикетки", Параметры);
    АктивныеЗадания.Добавить(НовоеЗадание);
КонецЦикла;

Решение 3: Системные настройки и обновление платформы

Если программные методы не помогают, следует обратить внимание на инфраструктурные аспекты:

  1. Обновление платформы: Это наиболее рекомендуемый путь. Ошибки потокобезопасности при работе с PDF активно исправлялись в версиях 8.3.18.1201 и выше, а также в ветке 8.3.20. Если есть возможность, перейдите на более свежий релиз.
  2. Настройка лимитов памяти: Увеличьте значение "Безопасный расход памяти за один вызов" в консоли администрирования кластера 1С. Также рассмотрите возможность увеличения количества рабочих процессов (rphost) на сервере, чтобы распределить нагрузку.
  3. Проверка прав доступа: Убедитесь, что у пользователя, под которым запущена служба 1C:Enterprise 8.3 Server Agent, есть полные права на папку временных файлов и целевую директорию записи.
  4. Шрифты в Linux: Если используется ОС Linux, установите пакеты шрифтов Microsoft (ttf-mscorefonts-installer) и убедитесь, что библиотека fontconfig настроена корректно. Иногда помогает предварительная генерация одного PDF-документа в один поток при старте сервера для инициализации кэша шрифтов.

Резюме

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

← На главную