При разработке в среде «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда один и тот же общий модуль должен обслуживать и интерактивные действия пользователя (на клиенте), и автоматические процессы (регламентные задания на сервере). Проблема возникает, когда в коде присутствуют обращения к переменным модуля приложения или глобальным переменным, которые доступны только в клиентском контексте. Если этот код попытается выполнить регламентное задание, система выдаст ошибку, так как на сервере этих переменных попросту не существует.
Рассмотрим подробнее, как правильно «спрятать» такой код от регламентного задания, разберем возможности препроцессора и программные методы проверки контекста.
Первое, что часто приходит в голову начинающему разработчику — это использование директив препроцессора. Проанализируем типичную ошибку: попытку использовать конструкцию #Если Сервер Тогда.
Важно понимать, что регламентные задания всегда выполняются на стороне сервера. Обычный вызов серверного метода из формы пользователя и запуск кода планировщиком заданий происходят в одном и том же контексте — серверном. Поэтому директива #Если Сервер Тогда не скроет код от регламентного задания, а наоборот, заставит систему компилировать его для исполнения на сервере.
Если «плохой» кусок кода содержит обращения к клиентским методам (например, Предупреждение() или переменные модуля приложения в Обычных формах), то при компиляции на сервере возникнет синтаксическая ошибка. Чтобы этого избежать, мы должны использовать обратную логику.
Если нам нужно, чтобы код вообще не компилировался на стороне сервера (включая регламентные задания), мы должны явно указать компилятору пропустить этот участок. Для этого подходят директивы #Если Клиент Тогда или #Если НЕ Сервер Тогда.
Разберем пример:
#Если НЕ Сервер Тогда
// Этот код будет виден только на клиенте (в толстом или тонком клиенте)
// Здесь можно безопасно обращаться к переменным модуля приложения
ЗначениеПараметра = ГлобальнаяПеременнаяКлиента;
ОткрытьФорму("Обработка.МояОбработка.Форма");
#КонецЕсли
При таком подходе, когда регламентное задание начнет компилировать общий модуль, оно просто «не увидит» блок внутри инструкции. Это самый надежный способ избежать ошибок компиляции, связанных с недоступными переменными.
Иногда возникают ситуации, когда код синтаксически корректен для сервера, но его выполнение именно в рамках регламентного задания нежелательно по логике работы программы. Поскольку препроцессор работает на этапе компиляции и не знает, КТО именно вызывает метод, нам необходимо выполнить проверку в процессе выполнения (Runtime).
Проанализируем ситуацию: как отличить обычный серверный вызов от регламентного? Регламентные задания в 1С всегда выполняются в контексте фоновых заданий. Мы можем использовать метод ФоновыеЗадания.ПолучитьТекущееФоновоеЗадание().
Рассмотрим, как это реализовать программно:
Функция ВыполнитьДействие() Экспорт
// Проверяем, не запущено ли исполнение в фоновом/регламентном режиме
ТекущееЗадание = ФоновыеЗадания.ПолучитьТекущееФоновоеЗадание();
Если ТекущееЗадание = Неопределено Тогда
// Код выполняется в обычном сеансе (не фоновом)
// Здесь можно выполнять действия, не предназначенные для регламентных заданий
ВыполнитьСпецифическуюЛогику();
Иначе
// Мы внутри фонового или регламентного задания
// Можно дополнительно проверить имя задания, если нужно
Если ТекущееЗадание.Метаданные.Имя = "МоеРегламентноеЗадание" Тогда
Возврат; // Выходим, если это наше задание
КонецЕсли;
КонецЕсли;
КонецФункции
Этот метод позволяет гибко управлять логикой, но помните: он не спасает от ошибок компиляции. Если внутри условия будет обращение к ГлобальнаяПеременнаяКлиента, модуль всё равно не скомпилируется на сервере.
Существует еще один «хитрый» способ — использование оператора Выполнить или функции Вычислить. Этот метод позволяет спрятать код от компилятора, превратив его в обычную строку текста.
Выясним, как это работает на практике:
Если НЕ ЭтоФоновоеЗадание() Тогда
// Код в строке не проверяется при загрузке модуля
ТекстКода = "Результат = ПеременнаяМодуляПриложения.Значение;";
Выполнить(ТекстКода);
КонецЕсли;
В данном примере система попытается скомпилировать и исполнить код только в момент вызова команды Выполнить. Если условие Если не выполняется (например, в регламентном задании), то и попытки обращения к переменной не будет. Однако злоупотреблять этим методом не стоит, так как он затрудняет отладку и поиск ошибок.
Вместо того чтобы пытаться скрыть «плохой» код, лучше следовать правилам качественной разработки в 1С:
ПараметрыСеанса. Они специально созданы для хранения глобальных данных сеанса.ОбщегоНазначения.ЭтоСеансФоновогоЗадания(), если ваша конфигурация построена на базе БСП.Подведем итог: чтобы код не мешал работе регламентного задания, используйте #Если НЕ Сервер Тогда для защиты от ошибок компиляции и ФоновыеЗадания.ПолучитьТекущееФоновоеЗадание() для управления логикой выполнения. Проектируйте систему так, чтобы серверная логика не зависела от клиентского контекста.