В практике разработки на платформе «1С:Предприятие» программисты часто сталкиваются с коварной ситуацией: написанный код отлично отрабатывает при нажатии на кнопку в обработке или при принудительном запуске из консоли регламентных заданий, но наотрез отказывается работать автоматически по расписанию. В Журнале регистрации при этом может лаконично отображаться статус «Задание выполнено с ошибками» без вывода подробного стека вызовов, либо изменения в базе данных попросту не фиксируются.
В этой статье мы подробно разберем, почему возникает такое различие в поведении системы, как правильно настроить отладку фонового процесса и какие настройки безопасности платформы и Библиотеки Стандартных Подсистем (БСП) блокируют автоматическое выполнение вашего кода.
---
Прежде чем приступать к исправлению кода, нам необходимо увидеть реальную ошибку, которая происходит в фоновом сеансе. При ручном интерактивном запуске код выполняется в контексте текущего пользователя (в его сеансе), а автоматический запуск происходит в фоновом сеансе на сервере. Чтобы перехватить этот процесс отладчиком, выполним следующие действия:
ВыполнитьОбработкуПоРегламентномуЗаданию общего модуля ДополнительныеОтчетыИОбработки.Полезный совет: Чтобы быстро локализовать проблему, перед запуском задания выберите в меню конфигуратора Отладка -> Остановка по ошибке и установите флаг Останавливаться по ошибке. Это позволит отладчику автоматически замереть ровно на той строке, которая вызывает сбой в фоновом режиме.
---
Рассмотрим реальный пример кода, который вызывал ошибку у автора обсуждения при выполнении в фоновом режиме:
Процедура ОбойтиЗвонки() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТелефонныеЗвонкиИзУТ.НомерТелефона КАК Номер,
| ТелефонныеЗвонкиИзУТ.Пользователь КАК Пользователь,
| ТелефонныеЗвонкиИзУТ.ИД КАК ИД
|ИЗ
| РегистрСведений.ТелефонныеЗвонкиИзУТ КАК ТелефонныеЗвонкиИзУТ
|ГДЕ
| НЕ ТелефонныеЗвонкиИзУТ.БылЗвонок";
Выборка = Запрос.Выполнить.Выбрать();
Пока Выборка.Следующий() Цикл
ПозвонитьПоНомеру(Выборка.Пользователь, Выборка.Номер);
КонецЦикла;
КонецПроцедуры
И процедура отправки запроса в облачную АТС:
Процедура ПозвонитьПоНомеруОблачнаяТелефония(ДанныеЗвонка, Ошибка, Пользователь)
ДанныеПользователяАТС = ТелефонияСервер.ДанныеПользователяАТС(Пользователь);
// Ошибка происходит здесь:
ДанныеЗвонка.Пользователь.ВнутреннийНомер = ДанныеПользователяАТС.ВнутреннийНомер;
ТелефонияСервер.ДополнитьДанныеЗвонкаДаннымиПользователя(ДанныеЗвонка);
// Отправка HTTP-запроса...
КонецПроцедуры
При отладке фонового процесса на строке присвоения внутреннего номера возникает исключение: «Значение не является значением объектного типа (ВнутреннийНомер)». При этом при ручном запуске под Администратором всё работает корректно. Почему так происходит?
Существует три основные причины такого поведения:
В фоновом сеансе регламентного задания по умолчанию нет активного пользователя (либо назначен специальный служебный пользователь). Если в вашей системе настроен RLS, то запрос к регистру сведений настроек или справочнику Пользователи может вернуть пустой результат (или Неопределено), так как у фонового сеанса банально нет прав на просмотр этих записей. Функция ТелефонияСервер.ДанныеПользователяАТС() возвращает пустое значение, что приводит к краху при попытке обратиться к его свойствам через точку.
Если ваше регламентное задание реализовано в виде дополнительной (внешней) обработки, Библиотека Стандартных Подсистем по умолчанию запускает ее в безопасном режиме. В безопасном режиме действуют жесткие ограничения платформы:
УстановитьПривилегированныйРежим(Истина) просто игнорируется системой).HTTPСоединение, что критично для интеграции с АТС).Начиная с версии платформы 8.3.9, в системе работает механизм защиты от выполнения потенциально опасного кода во внешних файлах. При ручном запуске пользователю выводится интерактивное окно с вопросом «Разрешить запуск этой обработки?». При автоматическом запуске регламентного задания интерактивный диалог открыть невозможно, поэтому платформа превентивно блокирует работу опасных методов, аварийно завершая фоновое задание.
---
Для того чтобы регламентное задание корректно отрабатывало в автоматическом режиме по расписанию, выполним комплексную настройку системы и доработку кода.
Чтобы обойти ограничения прав доступа (RLS) при чтении настроек телефонии фоновым заданием, необходимо временно отключить проверку прав. Для этого нужно перенести вызов инструкции УстановитьПривилегированныйРежим в самое начало транзакции или выборки данных.
Модифицируем нашу процедуру:
Процедура ОбойтиЗвонки() Экспорт
// Включаем привилегированный режим в самом начале выполнения фонового процесса
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ..."; // Код запроса
// Дальнейшая логика обработки данных под полными правами без RLS
КонецПроцедуры
Если вы используете подсистему «Дополнительные отчеты и обработки», вам необходимо явно разрешить вашей обработке доступ к внешним ресурсам (в данном случае — к серверам телефонии):
Для стабильной работы фоновых задач рекомендуется привязать их к специально созданному системному пользователю:
РоботТелефонии).РоботТелефонии.Всегда проверяйте полученные из внешних функций структуры на заполненность, прежде чем обращаться к их реквизитам. Оберните потенциально опасные участки кода, связанные с внешними вызовами и HTTP-запросами, в блок обработки исключений:
Процедура ПозвонитьПоНомеруОблачнаяТелефония(ДанныеЗвонка, Ошибка, Пользователь)
ДанныеПользователяАТС = ТелефонияСервер.ДанныеПользователяАТС(Пользователь);
Если ДанныеПользователяАТС = Неопределено Тогда
Ошибка = "Не заполнены настройки телефонии для пользователя: " + СокрЛП(Пользователь);
ЗаписатьВЖурналРегистрации("Телефония.ОшибкаНастроек", УровеньЖурналаРегистрации.Ошибка,,, Ошибка);
Возврат;
КонецЕсли;
// Безопасная проверка наличия необходимых свойств
Если ТипЗнч(ДанныеЗвонка.Пользователь) = Тип("СправочникСсылка.Пользователи") Тогда
// Если Пользователь - это ссылка, а не структура, сначала инициализируем данные
КонецЕсли;
Попытка
// Блок отправки HTTP-запроса к АТС
Исключение
Ошибка = ОписаниеОшибки();
ЗаписатьВЖурналРегистрации("Телефония.ОшибкаЗапроса", УровеньЖурналаРегистрации.Ошибка,,, Ошибка);
КонецПопытки;
КонецПроцедуры
---
Разница в поведении регламентного задания при ручном и автоматическом запусках — это не «эзотерика» 1С, а логичное следствие работы механизмов безопасности платформы. Перенос кода в привилегированный режим, отключение защиты от опасных действий для служебного пользователя и корректная настройка разрешений БСП гарантируют стабильное и безотказное выполнение ваших фоновых процессов по заданному расписанию.