Часто разработчики сталкиваются с ситуацией, когда код идеально работает при ручном запуске (например, по кнопке из внешней обработки), но при выполнении по расписанию в виде регламентного задания выдает некорректные или устаревшие результаты. Проанализируем типичную ситуацию: регламентное задание формирует остатки товаров и выгружает их в Excel. При ручном запуске список товаров актуальный, а при фоновом — в файл попадают товары, которых давно нет на складе. Разберем по шагам, куда копать и как решать подобные проблемы.
Первое, на что необходимо обратить внимание — это контекст выполнения кода. Ручной запуск обработки всегда инициируется клиентским сеансом. Регламентное же задание выполняется в изолированном фоновом сеансе строго на сервере 1С.
Давайте рассмотрим, какие нюансы это за собой влечет:
USR1CV8). У этого системного пользователя могут отсутствовать права на запись в сетевые папки или доступ к локальным дискам, которые доступны вашему личному пользователю Windows.Проанализируем структуру запроса, который часто используется для получения остатков. Ошибки в логике запроса могут по-разному проявляться на клиенте и сервере при постобработке результатов. Посмотрим на пример кода с использованием левого соединения:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Номенклатура,
ВложенныйЗапрос.Код,
ВложенныйЗапрос.Остаток
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
ТоварыОстатки.Номенклатура КАК Номенклатура,
ТоварыОстатки.Номенклатура.Код КАК Код,
ТоварыОстатки.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ТоварыОрганизаций.Остатки(&ТекущаяДата, ) КАК ТоварыОстатки
ГДЕ
ТоварыОстатки.КоличествоОстаток > 0) КАК ВложенныйЗапрос
ПО СправочникНоменклатура.Ссылка = ВложенныйЗапрос.Номенклатура
ГДЕ
СправочникНоменклатура.ЭтоГруппа = ЛОЖЬ
При таком левом соединении, если по товару нет записей в регистре остатков, в колонке Остаток вернется значение NULL. Начинающие разработчики иногда пытаются обработать это значение уже при обходе результата запроса конструкциями вида Если Остаток = NULL ИЛИ Остаток <= 0 Тогда..., что является методологически неверным подходом.
Чтобы код работал предсказуемо и стабильно в любом контексте, всегда обрабатывайте NULL на уровне самого запроса с помощью функции ЕСТЬNULL. Изменим наш запрос:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Номенклатура,
ВложенныйЗапрос.Код,
ЕСТЬNULL(ВложенныйЗапрос.Остаток, 0) КАК Остаток
// ... остальной текст запроса ...
Теперь в выборку всегда гарантированно попадет число 0, а не пустой тип данных. Это исключит разное поведение кода при вычислении условий на клиенте и в фоне.
Если ваше регламентное задание формирует прайс-лист в Excel и отправляет его на FTP, рассмотрим нюансы серверной работы с этими технологиями. Если требуется настроить регулярную публикацию готовых файлов без написания собственного кода, можно задействовать программу для автоматической обработки и выгрузки прайс-листов по FTP.
Формирование Excel: Никогда не используйте COM-объекты (например, Excel.Application) внутри серверного кода. Серверная служба не имеет профиля рабочего стола (Desktop), и попытка открыть COM-объект приведет к зависанию фонового задания или ошибкам прав доступа DCOM. Вместо этого используйте встроенный платформенный объект ТабличныйДокумент. Вы можете программно заполнить его и сохранить напрямую в файл:
ТабДок = Новый ТабличныйДокумент;
// ... заполнение макета ...
ТабДок.Записать(ПолныйПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
Передача по FTP: Если при выгрузке на сервер приходят "кривые" файлы (обрезаются имена или бьются данные), обратите внимание на режим соединения. При инициализации объекта FTPСоединение в фоновом задании обязательно устанавливайте пассивный режим передачи. Активный режим часто конфликтует с NAT и корпоративными брандмауэрами, за которыми спрятан сервер 1С.
Соединение = Новый FTPСоединение(Сервер, Порт, Логин, Пароль, , Истина); // Истина = ПассивноеСоединение
Соединение.Записать(ПутьКФайлуЛокально, ПолноеИмяФайлаНаФтп);
Выясним истинную причину описанной в начале статьи проблемы. Разработчики проверили права, переписали запросы, проверили логи FTP, но результат оставался прежним: вручную выгружается корректный файл, а по расписанию на FTP появляется старый прайс-лист с несуществующими товарами.
Решение оказалось до идиотизма простым: база данных была недавно перенесена на новый сервер. На новом сервере все было настроено корректно, регламентные задания запускались и работали. Однако старый сервер (или тестовая копия базы) не был погашен!
Что происходило на самом деле:
Как избежать подобных ситуаций:
При копировании баз для тестирования или переносе рабочих баз на другие сервера необходимо жестко контролировать фоновые процессы. В консоли администрирования серверов 1С для любой копии базы всегда устанавливайте флаг «Блокировка регламентных заданий включена». Это гарантирует, что тестовая база случайно не отправит письма реальным клиентам, не выгрузит старые прайсы на сайт и не затрет актуальные данные на внешних FTP-серверах.
В современных конфигурациях, использующих БСП (Библиотеку стандартных подсистем), реализована защита от таких ситуаций: при смене расположения базы система сама спрашивает: «Информационная база перемещена или восстановлена из резервной копии?». Обязательно выбирайте вариант «Это копия информационной базы», чтобы 1С автоматически заблокировала работу с внешними ресурсами.