Почему при выгрузке файлов на FTP из регламентного задания они оказываются пустыми или затираются?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Анализ исходной ситуации

Рассмотрим сценарий, описанный в проблеме. У нас есть регламентное задание в конфигурации (например, «Управление торговлей» редакции 10.3), которое выполняется по расписанию раз в сутки. Алгоритм работы следующий:

  1. Формируется таблица данных (запрос к базе).
  2. Создается табличный документ и сохраняется в файл Excel в Папку №1.
  3. Файл копируется из Папки №1 в архивную Папку №2.
  4. Файл из Папки №1 отправляется на FTP-сервер.

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

Взглянем на фрагмент кода, отвечающий за сохранение:


ПолноеИмяФайла = КаталогВыгрузки + "\" + ИмяФайла + "_" + Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss") + ".xls";
ТабДок.Записать(ПолноеИмяФайла, ТипФайлаТабличногоДокумента.XLS97);
КопироватьФайл(ПолноеИмяФайла, КаталогВыгрузки2 + "\" + ИмяФайла + "_" + Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss") + ".xls");

Также используется процедура отправки на FTP:


МассивФайлов = НайтиФайлы(КаталогВыгрузки, "*.xls");
Для Каждого Файл ИЗ МассивФайлов Цикл
    Соединение.Записать(Файл.ПолноеИмя, Файл.Имя);
КонецЦикла;

Причина проблемы: «Атака клонов»

Если код работает верно при ручном запуске, но сбоит при автоматическом, и при этом файлы физически перезаписываются, наиболее вероятная причина — параллельная работа регламентного задания в копии базы данных.

Разберем механику ошибки:

  1. Системный администратор делает копию рабочей базы для разработки или тестов, но забывает отключить в ней выполнение регламентных заданий.
  2. Наступает время «Ч» (время по расписанию). Задание стартует одновременно и в рабочей базе (PROD), и в тестовой копии (TEST).
  3. Поскольку время на серверах синхронизировано, обе базы генерируют абсолютно одинаковое имя файла, так как оно базируется на текущей дате и времени с точностью до секунды: Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss").
  4. Рабочая база содержит данные за текущий день, поэтому она формирует большой отчет и начинает его запись на диск.
  5. Копия базы данных (сделанная вчера или ранее) не содержит данных за сегодня. Запрос возвращает пустой результат. Формирование отчета занимает миллисекунды.
  6. Происходит «гонка» (Race Condition): рабочая база пишет файл, а база-копия мгновенно создает файл с таким же именем (пустой, только с заголовком) и перезаписывает файл рабочей базы в той же сетевой папке.

Именно поэтому в Папке №2 (архив) файл может сохраниться нормальным (если рабочая база успела скопировать его до того, как копия базы перезаписала оригинал в Папке №1), а на FTP уходит пустой файл, созданный копией.

Как обнаружить и исправить проблему

Чтобы убедиться, что проблема именно в наличии копии, проанализируйте журнал регистрации или время изменения файлов. Если время создания и изменения совпадают до секунды, но данных нет — это явный признак перезаписи.

Решение 1: Администрирование (Самое важное)

При создании копий баз данных (особенно клиент-серверных) необходимо всегда блокировать выполнение регламентных заданий. В консоли администрирования серверов 1С при создании или изменении свойств информационной базы установите флаг «Блокировка регламентных заданий включена».

Если база файловая, убедитесь, что копия запускается не под пользователем, у которого инициируется обработка заданий, либо запустите её с ключом блокировки.

Решение 2: Программная защита в коде 1С

Даже если администраторы ошиблись, ваш код должен быть устойчив к таким ситуациям. Рассмотрим несколько методов защиты.

Использование временных файлов

Никогда не используйте общие статические папки для временного хранения файлов перед отправкой, если в этом нет строгой необходимости. Используйте механизм временных файлов. Платформа 1С создаст файл с уникальным именем в папке временных файлов конкретного пользователя ОС (или службы сервера 1С).

Изменим код сохранения:


// Вместо явного пути используем временный файл
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xls");
ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLS97);

// Отправляем на FTP
Попытка
    Соединение.Записать(ИмяВременногоФайла, ИмяФайлаНаСервере);
Исключение
    // Обработка ошибки
КонецПопытки;

// Удаляем временный файл, чтобы не засорять диск
УдалитьФайлы(ИмяВременногоФайла);

При таком подходе, даже если запустятся 10 копий баз, каждая создаст свой уникальный временный файл в своей временной директории, и они не пересекутся.

Проверка на «Копию»

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


// Пример проверки по имени сервера (условно)
Если Найти(СтрокаСоединенияИнформационнойБазы(), "MyProdServer") = 0 Тогда
    ЗаписьЖурналаРегистрации("РегламентныеЗадания", УровеньЖурналаРегистрации.Предупреждение, , , 
        "Запуск задания прерван: обнаружен запуск не на продуктивном сервере.");
    Возврат;
КонецЕсли;

Уникализация имен файлов

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


// Добавляем префикс или уникальный идентификатор
УникИмя = ИмяФайла + "_" + Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss") + "_" + Новый УникальныйИдентификатор;
ПолноеИмяФайла = КаталогВыгрузки + "\" + УникИмя + ".xls";

В этом случае вы получите два файла в папке: один полный, другой пустой. Ничего не затрется, и вы сразу поймете по количеству файлов, что задание выполняется дважды.

Выводы и рекомендации

Подводя итог, можно сформулировать основные правила для предотвращения подобных ошибок:

  1. Контроль копий: Всегда отключайте регламентные задания в копиях баз данных сразу после развертывания.
  2. Изоляция данных: Избегайте использования общих сетевых папок в качестве «буфера» для генерации файлов разными базами. Используйте ПолучитьИмяВременногоФайла().
  3. Мониторинг: Если логика подразумевает отправку пустых файлов (например, «нет продаж»), проверяйте внутри кода: если табличный документ пуст (количество строк равно высоте шапки), возможно, файл вообще не стоит создавать и отправлять.

Следуя этим правилам, вы исключите ситуацию «самозатирания» данных и сэкономите время на отладке.

← На главную