При разработке на платформе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда код, успешно работающий в обычной внешней обработке, внезапно выдает ошибку Метод объекта не обнаружен при запуске в рамках регламентного или фонового задания. Особенно это актуально для вызова экспортных процедур и функций, расположенных в модулях объектов (документов, справочников).
В этой статье мы подробно разберем, почему фоновое задание может «терять» процедуру модуля документа, проанализируем технические нюансы серверного контекста и рассмотрим оптимальные способы решения этой задачи.
Разберем самую элементарную, но часто встречающуюся ситуацию. Процедуры, описанные в модуле объекта, доступны только тогда, когда у нас есть экземпляр этого объекта в оперативной памяти. Если вы пытаетесь вызвать процедуру непосредственно от ссылки (ДокументСсылка), система закономерно выдаст ошибку.
Проанализируем пример кода, который может привести к ошибке:
// ОШИБОЧНЫЙ КОД
Выборка = Документы.РеализацияТоваровУслуг.Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь Выборка.Ссылка — это Ссылка, а не Объект
Выборка.Ссылка.МояЭкспортнаяПроцедура(); // Ошибка: Метод объекта не обнаружен
КонецЦикла;
Для исправления ситуации необходимо получить объект из ссылки. Рассмотрим правильный подход:
// ПРАВИЛЬНЫЙ КОД
Выборка = Документы.РеализацияТоваровУслуг.Выбрать();
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
ДокОбъект.МояЭкспортнаяПроцедура();
КонецЕсли;
КонецЦикла;
Важно помнить, что метод ПолучитьОбъект() может вернуть Неопределено, если у текущего пользователя фонового задания нет прав на этот документ или ссылка является «битой».
Фоновое задание всегда выполняется на сервере в неинтерактивном режиме. Это накладывает жесткие ограничения на доступность программного кода. Выясним, как инструкции препроцессора влияют на видимость методов.
Если ваша процедура в модуле объекта обернута в блок #Если Клиент Тогда, то при компиляции модуля на сервере (что и происходит в фоновом задании) эта процедура просто не будет включена в состав исполняемого кода. В результате сервер «не увидит» метод, даже если вы добавили ключевое слово Экспорт.
Проанализируем содержимое модуля объекта:
#Если Клиент Тогда
Процедура МояЭкспортнаяПроцедура() Экспорт
// Какой-то код
КонецПроцедуры
#КонецЕсли
В данном случае фоновое задание, работающее исключительно в контексте #Если Сервер Тогда, не найдет этот метод. Проверьте, чтобы процедура была доступна на сервере. Оптимально либо вообще не использовать инструкции препроцессора вокруг метода, если в нем нет специфичного клиентского кода, либо использовать #Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда.
Важный нюанс: Если внутри серверной процедуры вызываются методы, доступные только на клиенте (например, Предупреждение() или Вопрос()), модуль объекта вообще может не скомпилироваться на сервере, что также приведет к ошибкам выполнения в фоновом задании.
Как отмечалось в обсуждении, использование модуля менеджера часто является более «чистым» и производительным решением для фоновых заданий. Разберем, почему это так.
Для вызова процедуры из модуля объекта системе необходимо:
ДокументОбъект со всеми его табличными частями и дополнительными свойствами.Если вам нужно выполнить действие, которое не требует обязательного наличия всех данных объекта в памяти (например, массовое изменение статусов или формирование движений), лучше использовать Модуль менеджера. В этом случае вы обращаетесь к методу без создания объекта.
Рассмотрим пример трансформации кода. Вместо метода в модуле объекта:
// В Модуле менеджера документа
Процедура ОбработатьДокумент(СсылкаНаДокумент) Экспорт
// Логика обработки, используя Ссылку
КонецПроцедуры
Вызов в фоновом задании будет выглядеть так:
// Вызов через менеджер
Документы.РеализацияТоваровУслуг.ОбработатьДокумент(НужнаяСсылка);
Обратите внимание: в модуле менеджера по умолчанию все методы считаются серверными, поэтому дополнительные инструкции препроцессора там обычно не требуются, если вы не планируете вызывать их с тонкого клиента (что в управляемых формах запрещено для модулей менеджера без специальной настройки).
Фоновые задания запускаются под определенным пользователем. Если в регламентном задании не указан конкретный пользователь, оно может выполняться под системной учетной записью или пользователем с ограниченными правами.
Если включен механизм RLS (Restriction at Level of Security), то при попытке выполнить запрос или получить объект документа фоновое задание может просто «не увидеть» нужные записи. В результате ПолучитьОбъект() вернет Неопределено, и последующий вызов экспортного метода вызовет ошибку Метод объекта не обнаружен.
Выясним, как гарантировать выполнение кода независимо от прав. Для этого используем привилегированный режим:
Процедура ВыполнитьРегламентноеЗадание() Экспорт
УстановитьПривилегированныйРежим(Истина);
// Теперь код выполняется без проверки прав доступа RLS
Выборка = Документы.РеализацияТоваровУслуг.Выбрать();
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДокОбъект.МояЭкспортнаяПроцедура();
КонецЦикла;
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры
В редких случаях причиной может стать кэш серверного кластера 1С. Вы добавили слово Экспорт, сохранили конфигурацию и обновили базу, но фоновые задания продолжают использовать старую версию скомпилированного модуля.
Проанализируем шаги для исключения этой проблемы:
1C:Enterprise 8.3 Server Agent.Подведем итог. Если вы столкнулись с ошибкой Метод объекта не обнаружен в фоновом задании при обращении к модулю документа, пройдите по следующему чек-листу:
ДокументОбъект, а не у ДокументСсылка. Используйте ПолучитьОбъект().Экспорт в заголовке процедуры.#Если Клиент Тогда. Для фоновых заданий код должен быть доступен на сервере.Предупреждение, Вопрос или ОткрытьФорму.УстановитьПривилегированныйРежим(Истина), чтобы исключить влияние RLS.Соблюдение этих правил позволит избежать большинства проблем, связанных с контекстом выполнения серверного кода в 1С.