Разработчики в среде «1С:Предприятие 8» часто сталкиваются с ситуацией, когда внешняя обработка, запущенная интерактивно (вручную пользователем), работает абсолютно корректно, но при её выполнении в фоновом режиме или по расписанию начинают происходить странные вещи. Например, даты периода «плывут» или принимают пустые значения, а на почту вместо одного файла выгрузки приходят два — один с верными данными, а другой — с совершенно хаотичным заполнением.
В этой статье мы подробно разберем, почему возникает такое различие в поведении интерактивного сеанса и фонового задания, как устроена передача параметров в фоновые процессы в конфигурациях на базе Библиотеки стандартных подсистем (БСП) — таких как «1С:Управление торговлей 11», и как раз и навсегда решить проблемы с датами и дублированием файлов.
---
Проанализируем базовый механизм работы платформы с датами. Очень часто в коде внешних обработок для определения текущего момента времени или расчета границ периода используется стандартная функция ТекущаяДата(). При ручном запуске обработки на клиенте этот метод возвращает локальное время компьютера пользователя, что обычно и ожидает увидеть разработчик.
Однако при запуске этого же кода в фоновом задании контекст его выполнения кардинально меняется:
ТекущаяДата() на сервере возвращает локальное время операционной системы самого сервера.Решение: Для устранения этой проблемы всегда используйте метод ТекущаяДатаСеанса() вместо обычного ТекущаяДата(). Функция ТекущаяДатаСеанса() возвращает время, приведенное к часовому поясу конкретного сеанса, который для фонового задания настраивается в параметрах информационной базы или берется из настроек пользователя, под которым запущено регламентное задание.
---
Разберем по шагам, как хранятся данные во внешней обработке. Когда пользователь открывает обработку интерактивно, он заполняет реквизиты формы (например, выбирает период выгрузки «Дата начала» и «Дата окончания»). Эти значения записываются в реквизиты объекта обработки — ЭтотОбъект.ДатаНачала и ЭтотОбъект.ДатаОкончания.
Если в коде интерактивного запуска вызывается процедура экспорта, она обращается напрямую к свойствам ЭтотОбъект и получает заполненные даты. Но фоновое задание не имеет доступа к созданной на клиенте форме и экземпляру объекта обработки. Оно запускается в абсолютно новом, изолированном серверном сеансе.
При этом происходят следующие процессы:
'0001-01-01').ЭтотОбъект.ДатаНачала, он получает пустую дату. В результате обработка пытается выгрузить файлы за «все времена», что приводит к генерации огромных файлов с некорректными (непонятно откуда взявшимися) данными.Решение: Никогда не рассчитывайте на то, что фоновое задание «увидит» реквизиты обработки, заполненные пользователем. Все параметры (периоды, флаги, настройки выгрузки) необходимо явно сериализовать (например, упаковать в структуру) и передавать в фоновое задание при его создании. Внутри фонового задания эти параметры должны извлекаться и передаваться в качестве параметров процедур.
---
Рассмотрим ситуацию, когда при выполнении фонового задания на почту приходят два файла: один корректный, а второй — пустой или с неверным периодом. Это указывает на возникновение эффекта «двойного запуска» или конфликта механизмов БСП.
Выделим три основные причины дублирования:
А. Конфликт ручного запуска фонового задания и механизмов БСП.
В современных конфигурациях (таких как УТ 11) внешние обработки регистрируются в справочнике «Дополнительные отчеты и обработки». Если для команды настроен режим выполнения «Вызов серверного метода», БСП автоматически берет на себя запуск этой команды в фоновом режиме (длительная операция). Если внутри процедуры ВыполнитьКоманду() разработчик дополнительно вручную прописывает код создания фонового задания через ФоновыеЗадания.Выполнить(), происходит двойной старт. БСП запускает фоновое задание №1, а оно внутри себя порождает фоновое задание №2. Одно из них может получить параметры вызова, а второе выполнится с пустыми параметрами по умолчанию.
Б. Автоматический перезапуск (Retry) при сбоях.
У регламентных заданий в платформе «1С:Предприятие» есть свойство «Количество повторов при аварийном завершении». Если при первой попытке отправки почты произошел кратковременный сбой соединения, платформа считает выполнение неудачным и запускает задание повторно. Если при повторном старте параметры инициализировались некорректно (например, очистилось временное хранилище с параметрами сеанса), первая попытка могла успеть выгрузить правильный файл, а вторая создаст файл по умолчанию.
В. Запуск регламентных заданий в копии базы.
Если рабочая база была скопирована для целей тестирования или разработки, и на копии не была установлена блокировка регламентных заданий, фоновые выгрузки запустятся одновременно и в рабочей, и в тестовой базах. Обе базы отправят файлы на один и тот же почтовый адрес, но в тестовой базе данные могут быть устаревшими, что создаст иллюзию отправки некорректного файла из основной системы.
---
Для того чтобы избежать описанных проблем, рассмотрим правильную структуру кода внешней обработки. Мы должны использовать предопределенную процедуру БСП ВыполнитьКоманду(), корректно обрабатывать параметры выполнения и использовать сеансовое время.
Посмотрим на пример реализации модуля внешней обработки:
Процедура ВыполнитьКоманду(ИмяКоманды, ПараметрыВыполнения) Экспорт
// Определяем дату выполнения с учетом часового пояса сеанса
ТекущийМомент = ТекущаяДатаСеанса();
Если ИмяКоманды = "ВыгрузитьДанныеЗаПериод" Тогда
// 1. Извлекаем параметры, переданные из формы или настроек БСП
ДатаНачала = Неопределено;
ДатаОкончания = Неопределено;
Если ПараметрыВыполнения.Свойство("СопутствующиеПараметры") Тогда
ПараметрыВыполнения.СопутствующиеПараметры.Свойство("ДатаНачала", ДатаНачала);
ПараметрыВыполнения.СопутствующиеПараметры.Свойство("ДатаОкончания", ДатаОкончания);
КонецЕсли;
// 2. Если параметры не заданы (запуск по расписанию), рассчитываем их программно
Если Не ЗначениеЗаполнено(ДатаНачала) Тогда
// Например, выгружаем данные за вчерашний день
ДатаНачала = НачалоДня(ТекущийМомент - 24 * 60 * 60);
КонецЕсли;
Если Не ЗначениеЗаполнено(ДатаОкончания) Тогда
ДатаОкончания = КонецДня(ТекущийМомент - 24 * 60 * 60);
КонецЕсли;
// 3. Вызываем процедуру логики, передавая параметры явно
ВыполнитьЭкспортДанных(ДатаНачала, ДатаОкончания, ПараметрыВыполнения);
КонецЕсли;
КонецПроцедуры
Процедура ВыполнитьЭкспортДанных(Знач ДатаНачала, Знач ДатаОкончания, ПараметрыВыполнения)
// Вся работа с выборкой данных должна опираться только на переданные параметры
Выборка = Документы.РеализацияТоваровУслуг.Выбрать(ДатаНачала, ДатаОкончания);
Пока Выборка.Следующий() Цикл
// Логика формирования файлов выгрузки
КонецЦикла;
// Пример записи результата в структуру БСП
ПараметрыВыполнения.РезультатВыполнения.Вставить("СтатусВыполнения", "Успешно");
КонецПроцедуры
---
Выяснить истинную причину некорректного поведения фонового задания без отладчика крайне сложно. Разберем по шагам, как настроить автоматическое подключение отладчика к фоновым заданиям в конфигураторе:
ВыполнитьКоманду() вашей внешней обработки. Чтобы отладчик сработал, код обработки должен быть загружен в базу (если запуск идет через справочник дополнительных обработок), либо вы можете открыть обработку через файл в режиме отладки.ПараметрыВыполнения и текущее системное время в момент остановки выполнения.Дополнительно рекомендуется проанализировать Журнал регистрации. Отфильтруйте записи по событию «Фоновое задание» и обратите внимание на идентификаторы сеансов (UUID). Это позволит точно определить, сколько процессов запускалось одновременно, были ли аварийные завершения с последующими перезапусками и под какими учетными записями выполнялся код.
Используя приведенные архитектурные подходы и заменив привязку к локальному времени сервера на сеансовое время с явной передачей параметров, вы полностью исключите рассинхронизацию данных и добьетесь стабильной и предсказуемой работы ваших обработок в любом режиме запуска.