При разработке и отладке сложных механизмов в среде 1С:Предприятие часто возникает необходимость выносить тяжелые вычисления во внешних обработках в фоновые задания. Если информационная база развернута на одном сервере, эта задача решается тривиально через сохранение обработки во временный файл и вызов стандартных механизмов БСП или платформы. Однако в промышленных средах с многосерверными кластерами разработчики сталкиваются с серьезной проблемой: первое фоновое задание отрабатывает успешно, а последующие завершаются аварийно с ошибкой «Файл не обнаружен» или «Ошибка подключения внешних метаданных».
В этой статье мы подробно разберем, почему возникает эта ошибка, как функционирует кластер 1С при работе с временными файлами, и рассмотрим несколько эффективных способов решения этой проблемы без необходимости разворачивать общие сетевые ресурсы (NAS/DFS) для серверов кластера.
---
Проанализируем классический сценарий, который приводит к ошибке:
rphost).ДлительныеОперации.ЗапуститьВыполнениеВФоне, куда передается путь к созданному временному файлу на сервере.C:\Users\...\AppData\Local\Temp\...), но у них собственная изолированная файловая система. Файла обработки там физически нет, что и приводит к системной ошибке.Попытки решить проблему «в лоб» через метод ВнешниеОбработки.Подключить() на сервере-инициаторе также терпят неудачу при работе в фоне. Метод Подключить() регистрирует внешнюю обработку в оперативной памяти конкретного рабочего процесса rphost. Когда фоновое задание запускается на другом сервере (или даже в другом рабочем процессе того же сервера), оно ничего не знает об этой регистрации.
---
Самый надежный и архитектурно правильный способ решения проблемы в рабочей базе — отказаться от прямого открытия файла с диска в пользу справочника дополнительных обработок.
Если обработка зарегистрирована в справочнике БСП ДополнительныеОтчетыИОбработки, двоичные данные файла обработки хранятся непосредственно в базе данных (в защищенном хранилище). Механизмы БСП автоматически синхронизируют и извлекают эти данные на любом сервере кластера, где бы ни запустилось фоновое задание.
Рассмотрим, как выглядит вызов фонового задания через БСП в этом случае:
ПараметрыВыполнения = Новый Структура;
ПараметрыВыполнения.Вставить("ДополнительнаяОбработкаСсылка", СсылкаНаОбъектСправочника);
ПараметрыВыполнения.Вставить("ИмяМетода", "ВыполнитьДлительнуюОперацию");
ПараметрыВыполнения.Вставить("ПараметрыВыполнения", ВашаСтруктураПараметров);
ПараметрыВыполнения.Вставить("ЭтоВнешняяОбработка", Истина);
РезультатФоновогоЗадания = ДлительныеОперации.ЗапуститьВыполнениеВФоне(
УникальныйИдентификатор,
"ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки",
ПараметрыВыполнения,
"Выполнение длительной операции на сервере кластера"
);
При таком подходе БСП сама возьмет на себя задачу извлечения двоичных данных обработки из базы данных на том сервере, который выделил процесс под фоновое задание, временно подключит ее и выполнит нужный метод.
Минус этого подхода: Он неудобен на этапе активной разработки и отладки, когда код обработки меняется каждые несколько минут, и постоянное обновление элемента справочника в пользовательском режиме замедляет работу программиста.
---
Если нам необходимо сохранить возможность запуска обработки «из файла» без ее предварительной регистрации в справочниках БСП, мы можем обойти ограничение файловой системы с помощью платформенного механизма Временного хранилища. Данные во временном хранилище реплицируются между всеми рабочими серверами кластера 1С.
Разберем по шагам, как реализовать этот алгоритм:
Шаг 1. Подготовка и передача данных с клиента на сервер
На стороне клиента (или сервера-инициатора) мы считываем файл внешней обработки в объект ДвоичныеДанные и помещаем его во временное хранилище. При этом крайне важно привязать адрес хранилища к уникальному идентификатору формы или фонового задания, чтобы платформа не очистила эти данные до момента старта фонового процесса.
&НаСервере
Функция ПодготовитьОбработкуКПередаче(ПутьКФайлу)
// Считываем обработку в двоичные данные
ДвоичныеДанныеОбработки = Новый ДвоичныеДанные(ПутьКФайлу);
// Помещаем во временное хранилище с привязкой к УникальномуИдентификатору формы
АдресВХ = ПоместитьВоВременноеХранилище(ДвоичныеДанныеОбработки, УникальныйИдентификатор);
Возврат АдресВХ;
КонецФункции
Шаг 2. Разработка процедуры-обертки для фонового задания
Поскольку стандартный метод БСП ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки ожидает имя файла, мы напишем собственный метод-прослойку в общем модуле (например, в модуле КастомныеПроцедурыСервер с установленными свойствами "Сервер", "Вызов сервера"). Этот метод будет выполняться уже внутри контекста фонового задания.
Процедура ВыполнитьОбработкуИзХранилища(Параметры, АдресРезультата) Экспорт
АдресВХ = Параметры.АдресВХ;
ИмяМетода = Параметры.ИмяМетода;
ПараметрыМетода = Параметры.ПараметрыМетода;
// Получаем двоичные данные обработки из временного хранилища
ДвоичныеДанныеОбработки = ПолучитьИзВременногоХранилища(АдресВХ);
// Получаем имя временного файла на ТОМ сервере, где сейчас запущено фоновое задание
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("epf");
// Записываем двоичные данные в локальный файл текущего сервера
ДвоичныеДанныеОбработки.Записать(ИмяВременногоФайла);
// Безопасно подключаем и создаем объект внешней обработки
ИмяОбработки = ВнешниеОбработки.Подключить(ИмяВременногоФайла, , Ложь);
ОбработкаОбъект = ВнешниеОбработки.Создать(ИмяОбработки, Ложь);
// Вызываем целевой метод обработки
ВыполнитьМетодОбъекта(ОбработкаОбъект, ИмяМетода, ПараметрыМетода);
// Очищаем временный файл после выполнения
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
// Логируем ошибку удаления, если файл занят процессом
КонецПопытки;
КонецПроцедуры
Шаг 3. Инициализация фонового задания
Теперь мы можем запустить фоновое задание через стандартный интерфейс БСП, передав структуру параметров с адресом временного хранилища:
АдресВХ = ПодготовитьОбработкуКПередаче(Объект.ИспользуемоеИмяФайла);
ПараметрыЗапуска = Новый Структура;
ПараметрыЗапуска.Вставить("АдресВХ", АдресВХ);
ПараметрыЗапуска.Вставить("ИмяМетода", "ВыполнитьРасчетДанных");
ПараметрыЗапуска.Вставить("ПараметрыМетода", Новый Структура("ДатаНачала, ДатаОкончания", Объект.ДатаНачала, Объект.ДатаОкончания));
РезультатФоновогоЗадания = ДлительныеОперации.ЗапуститьВыполнениеВФоне(
УникальныйИдентификатор,
"КастомныеПроцедурыСервер.ВыполнитьОбработкуИзХранилища",
ПараметрыЗапуска,
"Параллельный расчет данных во внешних заданиях"
);
Этот способ является наиболее универсальным, так как он полностью независим от структуры физического кластера, не требует настройки общего сетевого диска и позволяет запускать неограниченное число параллельных фоновых заданий с гарантией того, что каждое из них успешно развернет файл обработки локально на своем рабочем сервере.
---
Если у вас нет возможности или желания вносить изменения в программный код системы (например, конфигурация находится на жесткой поддержке, а внешняя обработка разрабатывается сторонним подрядчиком), проблему можно решить на уровне администрирования кластера 1С:Предприятия.
Мы можем принудительно заставить кластер запускать все фоновые задания определенного типа только на том рабочем сервере, на котором инициируется сеанс пользователя и создаются временные файлы.
Рассмотрим порядок настройки через консоль администрирования кластера (утилиту MMC или rac):
Фоновое задание (или конкретный сервис BackgroundJob.CommonModule).Назначать.Не назначать.Важное предупреждение: Данный метод решает проблему с отсутствием файлов, однако он полностью нивелирует преимущества многосерверного кластера в плане балансировки нагрузки. Сервер, на котором запрещен запуск фоновых заданий, перестанет участвовать в параллельных вычислениях, что может привести к деградации производительности при высокой активности пользователей.
---
Выбор оптимального подхода зависит от стадии жизненного цикла вашей разработки: