В практике разработки и администрирования 1С часто возникают ситуации, которые на первый взгляд кажутся мистическими. Код написан верно, логика проверена, при ручном запуске все работает идеально, но при автоматическом выполнении результат оказывается некорректным. Разберем одну из таких ситуаций: при формировании файлов Excel регламентным заданием и их последующей отправке на FTP, файлы оказываются «битыми» или пустыми (содержат только шапку), хотя в соседней папке архива они сохраняются корректно.
Рассмотрим сценарий, описанный в проблеме. У нас есть регламентное задание в конфигурации (например, «Управление торговлей» редакции 10.3), которое выполняется по расписанию раз в сутки. Алгоритм работы следующий:
В результате мы наблюдаем странную картину: в архивной папке файлы заполнены данными корректно, а в папке отправки (и, соответственно, на FTP) файлы практически пустые — содержат только служебные строки заголовка и подвала.
Взглянем на фрагмент кода, отвечающий за сохранение:
ПолноеИмяФайла = КаталогВыгрузки + "\" + ИмяФайла + "_" + Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss") + ".xls";
ТабДок.Записать(ПолноеИмяФайла, ТипФайлаТабличногоДокумента.XLS97);
КопироватьФайл(ПолноеИмяФайла, КаталогВыгрузки2 + "\" + ИмяФайла + "_" + Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss") + ".xls");
Также используется процедура отправки на FTP:
МассивФайлов = НайтиФайлы(КаталогВыгрузки, "*.xls");
Для Каждого Файл ИЗ МассивФайлов Цикл
Соединение.Записать(Файл.ПолноеИмя, Файл.Имя);
КонецЦикла;
Если код работает верно при ручном запуске, но сбоит при автоматическом, и при этом файлы физически перезаписываются, наиболее вероятная причина — параллельная работа регламентного задания в копии базы данных.
Разберем механику ошибки:
Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss").Именно поэтому в Папке №2 (архив) файл может сохраниться нормальным (если рабочая база успела скопировать его до того, как копия базы перезаписала оригинал в Папке №1), а на FTP уходит пустой файл, созданный копией.
Чтобы убедиться, что проблема именно в наличии копии, проанализируйте журнал регистрации или время изменения файлов. Если время создания и изменения совпадают до секунды, но данных нет — это явный признак перезаписи.
Решение 1: Администрирование (Самое важное)
При создании копий баз данных (особенно клиент-серверных) необходимо всегда блокировать выполнение регламентных заданий. В консоли администрирования серверов 1С при создании или изменении свойств информационной базы установите флаг «Блокировка регламентных заданий включена».
Если база файловая, убедитесь, что копия запускается не под пользователем, у которого инициируется обработка заданий, либо запустите её с ключом блокировки.
Решение 2: Программная защита в коде 1С
Даже если администраторы ошиблись, ваш код должен быть устойчив к таким ситуациям. Рассмотрим несколько методов защиты.
Никогда не используйте общие статические папки для временного хранения файлов перед отправкой, если в этом нет строгой необходимости. Используйте механизм временных файлов. Платформа 1С создаст файл с уникальным именем в папке временных файлов конкретного пользователя ОС (или службы сервера 1С).
Изменим код сохранения:
// Вместо явного пути используем временный файл
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xls");
ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLS97);
// Отправляем на FTP
Попытка
Соединение.Записать(ИмяВременногоФайла, ИмяФайлаНаСервере);
Исключение
// Обработка ошибки
КонецПопытки;
// Удаляем временный файл, чтобы не засорять диск
УдалитьФайлы(ИмяВременногоФайла);
При таком подходе, даже если запустятся 10 копий баз, каждая создаст свой уникальный временный файл в своей временной директории, и они не пересекутся.
В код регламентного задания полезно добавить проверку. Это может быть проверка строки соединения или специальной константы, которую вы меняете вручную только в рабочей базе.
// Пример проверки по имени сервера (условно)
Если Найти(СтрокаСоединенияИнформационнойБазы(), "MyProdServer") = 0 Тогда
ЗаписьЖурналаРегистрации("РегламентныеЗадания", УровеньЖурналаРегистрации.Предупреждение, , ,
"Запуск задания прерван: обнаружен запуск не на продуктивном сервере.");
Возврат;
КонецЕсли;
Если вам все же необходимо сохранять файлы в общую папку, сделайте имена файлов уникальными, добавив к ним идентификатор, который позволит отличить файл рабочей базы от файла копии.
// Добавляем префикс или уникальный идентификатор
УникИмя = ИмяФайла + "_" + Формат(ДатаОкончания, "ДФ=yyyyMMddhhmmss") + "_" + Новый УникальныйИдентификатор;
ПолноеИмяФайла = КаталогВыгрузки + "\" + УникИмя + ".xls";
В этом случае вы получите два файла в папке: один полный, другой пустой. Ничего не затрется, и вы сразу поймете по количеству файлов, что задание выполняется дважды.
Подводя итог, можно сформулировать основные правила для предотвращения подобных ошибок:
ПолучитьИмяВременногоФайла().Следуя этим правилам, вы исключите ситуацию «самозатирания» данных и сэкономите время на отладке.