Как загрузить файл регламентным заданием в 1С, если время его появления заранее неизвестно?

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

В практической работе разработчика 1С часто возникает задача автоматической загрузки данных из внешних систем. Классический сценарий: сторонняя программа (например, WMS, CRM или сайт) выгружает файл обмена в общий сетевой каталог, а решение на базе 1С должно его подхватить и обработать. Однако на практике время появления этого файла часто сдвигается из-за задержек на стороне отправляющей системы. Если регламентное задание 1С настроено на строго фиксированное время, оно может отработать «вхолостую» и завершиться до фактического появления файла.

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

Вариант 1. Использование платформенного механизма «Повторять при аварийном завершении»

Это самый простой и быстрый способ реализации ожидания, предложенный участниками обсуждения. Платформа 1С:Предприятие 8 поддерживает автоматический перезапуск регламентных заданий в случае возникновения ошибок в процессе их выполнения.

Рассмотрим алгоритм настройки данного механизма по шагам:

  1. Откроем конфигуратор и найдем нужное нам регламентное задание в ветке метаданных РегламентныеЗадания.
  2. В свойствах регламентного задания настроим параметры повторения:
    • Количество повторов при аварийном завершении — укажем желаемое число попыток (например, 10).
    • Интервал повтора при аварийном завершении — укажем время между попытками в секундах (например, 300 секунд для перезапуска каждые 5 минут).
  3. В коде обработчика регламентного задания пропишем генерацию исключения, если файл в каталоге не обнаружен.

Посмотрим на пример программной реализации этого подхода:


Процедура ВыполнитьЗагрузкуФайла() Экспорт

    ПутьККаталогу = "D:\Exchange\Input\";
    МаскаФайла = "*_nonDMA.xls";
    
    НайденныеФайлы = НайтиФайлы(ПутьККаталогу, МаскаФайла);
    
    Если НайденныеФайлы.Количество() = 0 Тогда
        // Файла нет. Вызываем исключение, чтобы платформа перезапустила задание по расписанию повтора
        ВызватьИсключение "Файл для импорта не найден в каталоге " + ПутьККаталогу + ". Повторная попытка через 5 минут.";
    КонецЕсли;
    
    // Если файл найден, выполняем стандартную загрузку
    Для Каждого Файл Из НайденныеФайлы Цикл
        ОбработатьФайлИмпорта(Файл.ПолноеИмя);
    КонецЦикла;

КонецПроцедуры

Анализ преимуществ и недостатков Варианта 1:

Данный подход привлекает своей простотой. Нам не нужно создавать дополнительные структуры данных для хранения состояний обмена. Однако у него есть существенные архитектурные минусы. Во-первых, при каждом неудачном поиске файла ЖурналРегистрации будет забиваться записями об ошибках (с красной иконкой), что усложнит мониторинг реальных системных сбоев. Во-вторых, этот механизм предназначен для обработки случайных технических сбоев (например, временных блокировок СУБД), а не для штатного ожидания бизнес-событий.

Вариант 2. Программный контроль статуса загрузки через Регистр сведений (Рекомендуемый метод)

Более надежный и гибкий подход заключается в частом запуске регламентного задания по обычному расписанию (например, каждые 10 минут в интервале с 4:20 до 7:00) и сохранении статуса загрузки в специальный РегистрСведений. Если за сегодня файл уже был успешно загружен, регламентное задание будет мгновенно завершаться без ошибок и лишних действий.

Разберем создание структуры данных. Создадим непериодический регистр сведений ИсторияЗагрузкиФайлов со следующими реквизитами:

Проанализируем программный код, реализующий этот алгоритм. Мы будем использовать метод НайтиФайлы, выполнять проверку наличия записи в регистре, а также обрабатывать файлы корректно:


Процедура ВыполнитьЗагрузкуФайлаСКонтролемСтатуса() Экспорт

    ТекущаяДатаСреза = НачалоДня(ТекущаяДата());
    
    // 1. Проверяем, был ли уже выполнен импорт за сегодня
    Если ИмпортЗаСегодняВыполнен(ТекущаяДатаСреза) Тогда
        // Завершаем работу тихо и штатно, чтобы не перегружать сервер
        Возврат;
    КонецЕсли;
    
    // 2. Ищем файл на диске
    ПутьККаталогу = "D:\Exchange\Input\";
    МаскаФайла = "*_nonDMA.xls";
    НайденныеФайлы = НайтиФайлы(ПутьККаталогу, МаскаФайла);
    
    Если НайденныеФайлы.Количество() = 0 Тогда
        // Файла еще нет — это нормальная рабочая ситуация.
        // Записываем информационное сообщение в лог и выходим без ошибки.
        ЗаписатьДанныеВЛог("Файл импорта не найден. Ожидаем следующий запуск по расписанию.");
        Возврат;
    КонецЕсли;
    
    // 3. Файл найден. Начинаем обработку
    Для Каждого Файл Из НайденныеФайлы Цикл
        
        // Защита от незавершенного копирования
        Если ФайлЗанятДругимПроцессом(Файл.ПолноеИмя) Тогда
            ЗаписатьДанныеВЛог("Файл " + Файл.Имя + " занят другим процессом. Возможно, он еще копируется. Пропускаем.");
            Продолжить;
        КонецЕсли;
        
        Попытка
            НачатьТранзакцию();
            
            ОбработатьФайлИмпорта(Файл.ПолноеИмя);
            
            // Фиксируем успешное выполнение в регистре сведений
            ЗаписатьСтатусЗагрузки(ТекущаяДатаСреза, Файл.Имя, Истина);
            
            // Переносим обработанный файл в папку архива, чтобы не обрабатывать его повторно
            ПереместитьФайлВАрхив(Файл);
            
            ЗафиксироватьТранзакцию();
            ЗаписатьДанныеВЛог("Файл " + Файл.Имя + " успешно загружен.");
            
        Исключение
            ОтменитьТранзакцию();
            ЗаписатьДанныеВЛог("Ошибка при обработке файла " + Файл.Имя + ": " + ОписаниеОшибки(), Истина);
        КонецПопытки;
        
    КонецЦикла;

КонецПроцедуры

Решение проблемы незавершенного копирования файла

Один из главных «подводных камней», упомянутых в обсуждении на форуме — ситуация, когда внешняя система начала копировать файл в папку обмена, но процесс еще не завершился. В этот момент 1С видит файл через НайтиФайлы, но при попытке чтения получит ошибку совместного доступа либо загрузит поврежденные данные.

Для гарантированной проверки того, что копирование завершено и файл свободен, мы можем использовать попытку монопольного доступа к нему. Самый простой и надежный способ в операционной системе Windows — попробовать переименовать или переместить файл сам в себя. Напишем вспомогательную функцию:


Функция ФайлЗанятДругимПроцессом(ПолноеИмяФайла)
    
    Попытка
        // Пытаемся переместить файл в то же самое место с тем же именем.
        // Если файл занят записью сторонней утилиты, ОС выдаст ошибку.
        ПереместитьФайл(ПолноеИмяФайла, ПолноеИмяФайла);
        Возврат Ложь; // Файл свободен, можно обрабатывать
    Исключение
        Возврат Истина; // Файл заблокирован или еще записывается
    КонецПопытки;
    
EndФункции

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

  1. Сначала полностью загружается файл данных, например data.xls.
  2. После полного завершения записи создается пустой файл-отметка, например data.ready.

В коде 1С вы настраиваете НайтиФайлы на поиск файла *.ready. Если он найден — вы гарантированно можете читать соответствующий файл данных.

Умные уведомления и контроль SLA (Принцип «Пульса»)

В сообщениях форума активно обсуждается вопрос своевременного информирования о проблемах. Если мы просто будем писать лог, администратор узнает о проблеме только при проверке. Нам необходимо настроить проактивное уведомление.

Рассмотрим две стратегии уведомлений:

  1. Отправка алертов при отсутствии файла к критическому времени (SLA). Наше задание работает каждые 10 минут. Если время уже перевалило за 07:00 утра, а отметка об успешной загрузке в регистре сведений ИсторияЗагрузкиФайлов для текущего дня все еще отсутствует — это повод отправить экстренное сообщение в Telegram или на Почту.
  2. Метод «Пульса» (Heartbeat). Каждое утро в определенное время система отправляет сводный отчет: «Обмен прошел успешно, загружено столько-то документов». Если отчет не пришел — значит, сломался либо сам механизм обмена, либо транспортный канал отправки сообщений.

Разберем пример реализации отправки уведомления в Telegram-канал при нарушении SLA:


Процедура ПроверитьНарушениеSLA() Экспорт

    ТекущееВремя = ТекущаяДата();
    КритическоеВремя = НачалоДня(ТекущееВремя) + 7 * 3600; // 07:00 утра
    
    Если ТекущееВремя >= КритическоеВремя Тогда
        Если Не ИмпортЗаСегодняВыполнен(НачалоДня(ТекущееВремя)) Тогда
            ОтправитьУведомлениеВТелеграм("Внимание! По состоянию на 07:00 файл импорта не был обнаружен и обработан!");
        КонецЕсли;
    КонецЕсли;

КонецПроцедуры

Процедура ОтправитьУведомлениеВТелеграм(ТекстСообщения)
    
    ТокенБота = "123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ";
    ИдентификаторЧата = "-100123456789";
    
    Соединение = Новый HTTPСоединение("api.telegram.org", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос("/bot" + ТокенБота + "/sendMessage");
    Запрос.УстановитьТелоИзСтроки("chat_id=" + ИдентификаторЧата + "&text=" + КодироватьСтроку(ТекстСообщения, СпособКодированияСтроки.КодировкаURL));
    
    Попытка
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    Исключение
        ЗаписатьДанныеВЛог("Не удалось отправить сообщение в Telegram: " + ОписаниеОшибки(), Истина);
    КонецПопытки;
    
КонецПроцедуры

Резюме и рекомендации

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

← На главную