При разработке механизмов обмена данными в 1С часто возникает ситуация, когда фоновое задание запускается сразу после записи документа, но сталкивается с тем, что данные еще не зафиксированы в базе (из-за транзакций) или документ не до конца сформирован. Рассмотрим, как избежать ошибок чтения и обеспечить надежную передачу файлов на FTP.
Основная проблема заключается в изоляции транзакций. Когда вы вызываете ФоновыеЗадания.Выполнить в момент записи документа, основной поток еще не завершил фиксацию данных в базе. В итоге фоновое задание, работая в отдельном потоке, «не видит» изменений или пытается прочитать данные, которые еще не прошли все проверки. Кроме того, одновременная запись в один файл двумя процессами может привести к повреждению данных.
Это самый надежный и профессиональный способ, рекомендуемый архитекторами 1С. Вместо прямого запуска задания при каждой записи, мы создаем промежуточное звено.
РегистрСведений (например, «ОчередьВыгрузкиНаFTP»).ПослеЗаписи объекта записываем в этот регистр ссылку на документ и признак «Готов к отправке».РегламентноеЗадание, которое работает по расписанию, опрашивает этот регистр и выполняет выгрузку.Преимущества: если FTP-сервер недоступен, задание не «умрет», а повторит попытку при следующем запуске. Также это полностью исключает проблемы с транзакциями.
Если вы хотите запускать задание «на лету», необходимо сделать его «умным». Вместо мгновенной выгрузки, заставьте задание ждать завершения транзакции записи основного документа.
Рассмотрим пример кода, который делает проверку версии данных, чтобы убедиться, что документ полностью записан:
Процедура ВыполнитьВыгрузку(СсылкаНаДокумент, НоваяВерсияДанных) Экспорт
КоличествоПопыток = 0;
Пока Истина Цикл
// Добавляем искусственную паузу, чтобы дать транзакции завершиться
ОбъектРасширения.Спать(1000);
ТекущаяВерсияДанных = ПолучитьВерсиюДанных(СсылкаНаДокумент);
// Если версия совпадает, значит документ успешно записан
Если ТекущаяВерсияДанных = НоваяВерсияДанных Тогда
ВыполнитьВыгрузкуНаFTP(СсылкаНаДокумент);
Прервать;
КонецЕсли;
КоличествоПопыток = КоличествоПопыток + 1;
Если КоличествоПопыток > 5 Тогда
ЗаписатьВЖурнал("Ошибка: превышено время ожидания записи");
Возврат;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если необходимо дождаться выполнения определенного процесса одной строкой кода, можно использовать метод ОжидатьЗавершения. Однако помните, что это блокирующая операция, и её следует применять с осторожностью:
// Получаем фоновое задание по наименованию и ждем его завершения
СписокЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Новый Структура("Наименование", "Выгрузка заказ"));
Если СписокЗаданий.Количество() > 0 Тогда
СписокЗаданий[0].ОжидатьЗавершения(60); // Ждем до 60 секунд
КонецЕсли;
Разберем основные принципы, которые помогут вам избежать проблем:
Используя комбинацию методов РегистрСведений для накопления задач и РегламентноеЗадание для их обработки, вы создадите стабильную систему, которая не боится сбоев сети и не перегружает базу данных блокировками.