Как определить текущий режим работы 1С: OData или фоновое задание?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом
← На главную

При работе с информационными системами на базе 1С:Предприятие 8.3, особенно в условиях интеграции с внешними сервисами и использования асинхронных операций, перед разработчиками часто встает задача определения текущего контекста выполнения кода. Рассмотрим, как мы можем узнать, является ли текущий режим работы OData-сеансом или фоновым заданием, и почему это так важно.

Одной из распространенных сложностей является то, что стандартная функция ТекущийРежимЗапуска() не всегда предоставляет достаточную детализацию. Например, если в новой версии конфигурации 1С:Зарплата и Управление Персоналом (ЗУП) проведение документов вынесено в фон, то при записи в фоновом режиме ТекущийРежимЗапуска() может возвращать Неопределено. Это не позволяет нам однозначно отличить запуск через OData от фонового задания, что критически важно для корректной логики работы обмена данными.

Зачем нам нужно определять режим работы?

Основная причина для точного определения режима работы кроется в управлении обменом данными. Представьте ситуацию: данные приходят в 1С через OData. Если при записи этих данных система автоматически начинает записывать их же в регистр для обмена, то эти данные будут отправлены обратно во внешний сервис или в другую базу, а затем снова загружены, что приведет к бесконечному циклу обмена. Для предотвращения таких ситуаций нам необходимо:

  1. Избежать зацикливания обмена: Если документ создан или изменен через OData, его не нужно регистрировать для последующего обмена, чтобы он не ушел обратно.
  2. Сохранить актуальную информацию об ошибках: В отличие от установки флага ОбменДанными.Загрузка = Истина, который может скрывать ошибки или отключать часть логики, нам иногда необходимо знать о проблемах в моменте, а не подавлять их.
  3. Корректно управлять ответственными: Если мы используем служебного пользователя для всех операций OData, фактические ответственные в документах будут искажаться. Определение режима работы позволяет нам внедрять логику, которая учитывает этот аспект.

Решение 1: Использование ПолучитьТекущийСеансИнформационнойБазы().ИмяПриложения

Для надежного определения текущего режима работы мы можем воспользоваться системной функцией ПолучитьТекущийСеансИнформационнойБазы(). Эта функция возвращает объект, содержащий информацию о текущем сеансе информационной базы. Нас интересует свойство ИмяПриложения этого объекта.

Свойство ИмяПриложения представляет собой строку, которая идентифицирует тип приложения или сервиса, инициировавшего текущий сеанс. Рассмотрим основные значения, которые мы можем получить:

Используя эти значения, мы можем точно определить контекст выполнения и построить соответствующую логику. Давайте рассмотрим пример кода, который можно использовать в обработчиках объектов, например, в процедуре ПередЗаписью документа.


&НаСервере
// Функция для определения текущего режима работы на основе имени приложения сеанса
Функция ОпределитьРежимРаботы()

    // Получаем объект текущего сеанса информационной базы
    ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();

    // Получаем имя приложения, инициировавшего сеанс
    ИмяПриложенияСеанса = ТекущийСеанс.ИмяПриложения;

    // Анализируем имя приложения для определения режима
    Если ИмяПриложенияСеанса = "ODataConnection" Тогда
        // Сеанс инициирован OData-сервисом
        Возврат "OData";
    ИначеЕсли ИмяПриложенияСеанса = "JobScheduler" Тогда
        // Сеанс инициирован планировщиком заданий (фоновое задание)
        Возврат "ФоновоеЗадание";
    ИначеЕсли ИмяПриложенияСеанса = "1CV8" Тогда
        // Сеанс инициирован толстым или тонким клиентом
        Возврат "КлиентскоеПриложение";
    ИначеЕсли ИмяПриложенияСеанса = "WebClient" Тогда
        // Сеанс инициирован веб-клиентом
        Возврат "ВебКлиент";
    Иначе
        // Другие, менее распространенные режимы или неизвестный режим
        Возврат ИмяПриложенияСеанса; 
    КонецЕсли;

КонецФункции

// Пример использования в модуле объекта документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

    // Определяем текущий режим работы
    ТекущийРежим = ОпределитьРежимРаботы();

    // В зависимости от режима, выполняем различную логику
    Если ТекущийРежим = "OData" Тогда
        // Мы в OData-сеансе. Здесь не нужно записывать данные в регистр для обмена
        // или инициировать другую логику, которая может вызвать зацикливание.
        Сообщить("Документ записывается через OData. Логика регистрации изменений для обмена будет пропущена.", СтатусСообщения.Информация);
        
        // Например, мы можем установить флаг в дополнительных свойствах объекта,
        // который будет проанализирован в обработчиках движения или в процедурах регистрации изменений.
        ЭтотОбъект.ДополнительныеСвойства.Вставить("ЗагрузкаЧерезOData", Истина);

        // Если есть необходимость изменить ответственного на реального пользователя,
        // можно это сделать здесь, если информация о пользователе передается через OData
        // (например, в пользовательских HTTP-заголовках).
        // Пример: ЭтотОбъект.Ответственный = ПолучитьПользователяПоИмени(ПараметрыOData.ИмяПользователя);

    ИначеЕсли ТекущийРежим = "ФоновоеЗадание" Тогда
        // Код выполняется в фоне. Это может быть часть обмена или рутинная операция.
        Сообщить("Документ записывается в фоновом режиме.", СтатусСообщения.Информация);
        // Здесь также может потребоваться пропустить логику регистрации изменений,
        // если фоновое задание инициировано системой обмена.
        // Можно дополнительно анализировать контекст фонового задания, если это регламентное задание обмена.
        Если ОбменДанными.Загрузка Тогда // Если фоновое задание само по себе является частью загрузки обмена
            ЭтотОбъект.ДополнительныеСвойства.Вставить("ЗагрузкаЧерезOData", Истина); // Или другой флаг
        КонецЕсли;

    ИначеЕсли ТекущийРежим = "КлиентскоеПриложение" Или ТекущийРежим = "ВебКлиент" Тогда
        // Стандартная запись через клиентское приложение.
        // Здесь обычно включается вся логика регистрации изменений и других проверок.
        Сообщить("Документ записывается в клиентском режиме: " + ТекущийРежим, СтатусСообщения.Информация);
        // Стандартная логика, например, запись в регистр обмена
        // ПроверитьИЗарегистрироватьИзмененияДляОбмена(ЭтотОбъект);

    Иначе
        // Неизвестный режим работы, требует дополнительного анализа
        Сообщить("Документ записывается в неизвестном режиме: " + ТекущийРежим, СтатусСообщения.Внимание);
    КонецЕсли;

КонецПроцедуры

// В процедурах, отвечающих за регистрацию изменений для обмена (например, в модуле менеджера или в подписке на событие)
// Мы можем анализировать установленный флаг.
// Пример:
// Процедура ЗарегистрироватьИзмененияДляОбмена(ДокументСсылка)
//    Если ДокументСсылка.ДополнительныеСвойства.Свойство("ЗагрузкаЧерезOData") Тогда
//        Если ДокументСсылка.ДополнительныеСвойства.ЗагрузкаЧерезOData Тогда
//            Возврат; // Пропускаем регистрацию, так как это была загрузка через OData
//        КонецЕсли;
//    КонецЕсли;
//    // Выполняем стандартную регистрацию изменений
// КонецПроцедура

Решение 2: Использование HTTP-заголовка 1C_OData-DataLoadMode для управления загрузкой данных через OData

Помимо определения самого факта работы через OData, часто возникает необходимость указать, что текущая OData-операция является именно загрузкой данных, а не обычной операцией пользователя. Это очень полезно, когда мы хотим, чтобы операция через OData вела себя аналогично загрузке данных через механизм обмена, при котором свойство ОбменДанными.Загрузка равно Истина.

Платформа 1С:Предприятие поддерживает специальный HTTP-заголовок 1C_OData-DataLoadMode. Если этот заголовок установлен в значение true при выполнении операции записи через OData, платформа автоматически устанавливает свойство ОбменДанными.Загрузка в Истина для текущей транзакции. Это позволяет нам централизованно управлять логикой, которая должна быть отключена при массовой загрузке данных, например, автоматической регистрацией изменений для обмена, проверками уникальности, отправкой уведомлений и т.д.

Таким образом, если мы получаем данные через OData и при этом хотим, чтобы система обрабатывала их как "загрузку", мы можем передать этот заголовок. Затем в нашем коде мы можем проверить и ИмяПриложения, и состояние ОбменДанными.Загрузка.


&НаСервере
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

    // Шаг 1: Определяем основной режим работы сеанса
    ИмяПриложенияСеанса = ПолучитьТекущийСеансИнформационнойБазы().ИмяПриложения;

    Если ИмяПриложенияСеанса = "ODataConnection" Тогда
        // Мы в OData-сеансе. Теперь проверим, является ли это режимом загрузки данных.
        // Платформа 1С автоматически установит ОбменДанными.Загрузка = Истина,
        // если в HTTP-запросе был передан заголовок 1C_OData-DataLoadMode: true.
        Если ОбменДанными.Загрузка Тогда
            Сообщить("Документ записывается через OData в режиме загрузки данных (HTTP-заголовок 1C_OData-DataLoadMode = true).", СтатусСообщения.Информация);
            // Здесь мы можем явно отключить логику, которая записывает данные в регистры обмена,
            // или другую логику, которая должна срабатывать только при ручном вводе/обычном проведении.
            ЭтотОбъект.ДополнительныеСвойства.Вставить("ЭтоЗагрузкаДанных", Истина);
            // Пропускаем регистрацию изменений для обмена
            // ЗапретитьРегистрациюИзменений(ЭтотОбъект);
        Иначе
            Сообщить("Документ записывается через OData (стандартный режим, не режим загрузки данных).", СтатусСообщения.Информация);
            // Логика для обычных операций OData, не являющихся массовой загрузкой.
            // Возможно, здесь также нужно пропустить регистрацию, если OData всегда используется для первичного ввода,
            // но ОбменДанными.Загрузка в данном случае не была установлена.
            // Рекомендуется использовать флаг "ЭтоЗагрузкаДанных" для более явного управления.
            ЭтотОбъект.ДополнительныеСвойства.Вставить("ЭтоЗагрузкаДанных", Истина); // Допустим, мы считаем любую запись через OData загрузкой.
        КонецЕсли;
    ИначеЕсли ИмяПриложенияСеанса = "JobScheduler" Тогда
        Сообщить("Документ записывается в фоновом режиме.", СтатусСообщения.Информация);
        // Для фоновых заданий также может быть актуальна проверка ОбменДанными.Загрузка,
        // если фоновое задание вызывается в контексте обмена данными.
        Если ОбменДанными.Загрузка Тогда
            Сообщить("Фоновое задание работает в режиме загрузки данных.", СтатусСообщения.Информация);
            ЭтотОбъект.ДополнительныеСвойства.Вставить("ЭтоЗагрузкаДанных", Истина);
        КонецЕсли;
    Иначе
        Сообщить("Документ записывается в режиме: " + ИмяПриложенияСеанса, СтатусСообщения.Информация);
        // Стандартная логика для клиентских приложений
    КонецЕсли;

КонецПроцедуры

// Пример использования флага в обработчике ПриЗаписиДвижений, ПриПроведении, или в подписках на события
Процедура ПриЗаписиДвижений(РежимПроведения)

    // Проверяем, установлен ли флаг, что это была загрузка данных
    Если ЭтотОбъект.ДополнительныеСвойства.Свойство("ЭтоЗагрузкаДанных") И ЭтотОбъект.ДополнительныеСвойства.ЭтоЗагрузкаДанных Тогда
        Сообщить("Регистрация изменений для обмена пропущена, так как данные пришли через OData в режиме загрузки или из другого обменного процесса.", СтатусСообщения.Информация);
        // Мы можем здесь выполнить возврат, чтобы пропустить стандартную логику,
        // которая регистрирует изменения для механизмов обмена.
        Возврат;
    КонецЕсли;

    // Стандартная логика регистрации изменений для обмена, если это не загрузка
    // Например: ЗарегистрироватьИзмененияДляУзловОбмена(ЭтотОбъект, ВидДвижения);

КонецПроцедуры

Резюме и рекомендации

Для эффективного управления логикой в зависимости от контекста выполнения в 1С:Предприятие 8.3:

  1. Используйте ПолучитьТекущийСеансИнформационнойБазы().ИмяПриложения для определения основного режима работы сеанса (ODataConnection, JobScheduler, 1CV8 и т.д.).
  2. Если работа идет через OData и требуется эмулировать режим загрузки данных, используйте HTTP-заголовок 1C_OData-DataLoadMode: true. Это автоматически установит ОбменДанными.Загрузка = Истина, что позволит вашей логике реагировать на этот флаг.
  3. Для передачи дополнительных флагов или параметров между различными этапами записи/проведения документа (например, из ПередЗаписью в ПриЗаписиДвижений) активно используйте коллекцию ДополнительныеСвойства объекта.
  4. Всегда тщательно тестируйте свою логику во всех предполагаемых режимах работы, чтобы убедиться в корректности обработки данных и отсутствии нежелательных побочных эффектов, таких как зацикливание обмена или некорректное заполнение реквизитов.

Внедряя эти подходы, вы сможете создать более гибкую и устойчивую систему, способную адекватно реагировать на различные сценарии взаимодействия, будь то ручной ввод пользователя, фоновые операции или обмен данными через OData.

← На главную