Почему параметр сеанса сбрасывается в 0 при выполнении регламентного задания на сервере?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← К списку

Уважаемые коллеги, давайте вместе разберем одну из распространенных и порой неочевидных проблем при разработке на платформе 1С:Предприятие, а именно — неожиданный сброс значений параметров сеанса во время работы регламентных заданий или серверных вызовов. Мы проанализируем ситуацию, когда параметр сеанса, например, _дхбсп_УровеньЛога, который вы устанавливаете в 1, внезапно откатывается к 0, приводя к некорректной работе логирования.

Анализ проблемы: Повторные вызовы процедуры УстановкаПараметровСеанса()

Мы выясним причину, по которой параметр сеанса может быть сброшен. Наш опыт показывает, что наиболее частой причиной такого поведения является повторный и, возможно, неконтролируемый вызов процедуры УстановкаПараметровСеанса() в модуле сеанса. Давайте рассмотрим подробнее, почему это происходит.

Платформа 1С:Предприятие вызывает процедуру УстановкаПараметровСеанса() автоматически в двух основных случаях:

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

В нашей ситуации, когда параметр _дхбсп_УровеньЛога сбрасывается, мы видим следующую картину:

  1. В процедуре УстановкаПараметровСеанса() вы, возможно, безусловно устанавливаете ПараметрыСеанса._дхбсп_УровеньЛога = 0;
  2. В коде регламентного задания вы вызываете процедуру НачатьЛог(), которая увеличивает уровень лога:
    
    Процедура НачатьЛог() экспорт
        ПараметрыСеанса._дхбсп_УровеньЛога = ПараметрыСеанса._дхбсп_УровеньЛога + 1;
        ЛогВФайлИнформация("Увеличиваем уровень лога: " +_омдх_Отладка.ИнформацияОСтекеВызововСтрокой() );
    КонецПроцедуры
    
    После этого вызова _дхбсп_УровеньЛога становится равным 1, и первая запись в лог это подтверждает.
  3. Сразу после этого, в той же транзакции, при вызове другой серверной процедуры, например, ХранениеФайловВызовСервера.ДописатьТекстКФайлу(), происходит обращение к какому-либо другому параметру сеанса (например, к ПараметрыСеанса.ТекущийПользователь, если он не был инициализирован, или к любому другому), который еще не был установлен. Это приводит к повторному вызову УстановкаПараметровСеанса().
  4. Поскольку ваша процедура УстановкаПараметровСеанса() безусловно сбрасывает _дхбсп_УровеньЛога в 0, он снова принимает это значение, что приводит к некорректному логированию следующей строки.

Ключевой момент: мы видим, что сброс происходит в пределах одного и того же сеанса, между двумя вызовами логирования. Это прямо указывает на повторное срабатывание механизма инициализации параметров сеанса.

Решение 1: Внедрение "ленивой" (отложенной) инициализации параметров сеанса

Мы предлагаем вам наиболее эффективное и правильное решение проблемы — изменение логики инициализации параметров сеанса в процедуре УстановкаПараметровСеанса(). Нам необходимо реализовать так называемую "ленивую" или "отложенную" инициализацию. Это означает, что мы будем инициализировать параметры сеанса только тогда, когда это действительно необходимо, и только те, которые требует платформа.

Давайте разберем по шагам, как это реализовать:

  1. Проверяем параметр ТребуемыеПараметры: Внутри УстановкаПараметровСеанса() мы должны анализировать значение этого параметра.
    • Если ТребуемыеПараметры = Неопределено, это означает, что происходит установка нового соединения или получение из пула. В этом случае мы можем выполнить общую инициализацию всех необходимых параметров сеанса, если они еще не установлены.
    • Если ТребуемыеПараметры — это массив имен, значит, платформа просит нас инициализировать конкретные, неинициализированные параметры. В этом случае мы должны инициализировать только те параметры, которые перечислены в этом массиве.
  2. Инициализируем параметры только при необходимости: Для каждого параметра сеанса, который мы хотим инициализировать, мы должны сначала проверить, установлен ли он уже. Если параметр уже имеет значение, мы не должны его сбрасывать.

Посмотрим на пример кода для процедуры УстановкаПараметровСеанса() с учетом "ленивой" инициализации:


// Модуль сеанса
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры) Экспорт

    // Инициализация, если происходит установка нового соединения или получение из пула
    Если ТребуемыеПараметры = Неопределено Тогда
        // Здесь можно инициализировать все параметры, которые должны быть установлены при старте сеанса
        // Пример для _дхбсп_УровеньЛога:
        Если ПараметрыСеанса._дхбсп_УровеньЛога = Неопределено Тогда
            ПараметрыСеанса._дхбсп_УровеньЛога = 0;
        КонецЕсли;

        // Другие параметры, например, ТекущийПользователь
        Если ПараметрыСеанса.ТекущийПользователь = Неопределено Тогда
            ПараметрыСеанса.ТекущийПользователь = Пользователи.ТекущийПользователь();
        КонецЕсли;

        // И так далее для всех параметров, требующих инициализации при старте сеанса
        
    Иначе // ТребуемыеПараметры - это массив имен неинициализированных параметров
        // Инициализируем только те параметры, к которым произошло обращение и которые не инициализированы
        Для Каждого ИмяПараметра Из ТребуемыеПараметры Цикл
            Если ИмяПараметра = "_дхбсп_УровеньЛога" Тогда
                Если ПараметрыСеанса._дхбсп_УровеньЛога = Неопределено Тогда
                    ПараметрыСеанса._дхбсп_УровеньЛога = 0;
                КонецЕсли;
            ИначеЕсли ИмяПараметра = "ТекущийПользователь" Тогда
                Если ПараметрыСеанса.ТекущийПользователь = Неопределено Тогда
                    ПараметрыСеанса.ТекущийПользователь = Пользователи.ТекущийПользователь();
                КонецЕсли;
            // Добавляем другие параметры сеанса по аналогии
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;

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

Используя такую логику, мы гарантируем, что параметр _дхбсп_УровеньЛога будет установлен в 0 только в начале сеанса (или при первом обращении, если он был неинициализирован), но не будет сброшен, если он уже имеет другое значение (например, 1 после вызова НачатьЛог()), даже при повторных вызовах УстановкаПараметровСеанса() из-за обращения к другим неинициализированным параметрам.

Решение 2: Проверка на наличие ПараметрыСеанса.Очистить()

Хотя это менее вероятно, мы также должны рассмотреть возможность программного сброса параметров сеанса. Существует метод ПараметрыСеанса.Очистить(), который может быть вызван для всех параметров сеанса или для указанного списка.

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

Дополнительные замечания и рекомендации

Использование констант для значений по умолчанию

Если начальное значение параметра сеанса (например, _дхбсп_УровеньЛога) является константой, мы можем использовать ее в инициализации. Это сделает код более гибким и понятным.

Особенности работы с регламентными заданиями

Помните, что регламентные задания выполняются в отдельных фоновых сеансах. Это означает, что каждый запуск регламентного задания может инициировать свой собственный контекст сеанса и, соответственно, вызвать УстановкаПараметровСеанса(). Корректная "ленивая" инициализация критически важна для стабильной работы таких заданий.

Версия платформы 8.3.27

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

Временные "костыли" и их устранение

Временно вы могли использовать "костыли", такие как сверка параметра сеанса на входе и выходе из процедуры. Мы призываем вас заменить такие временные решения на описанную выше "ленивую" инициализацию. Это значительно повысит стабильность, надежность и сопровождаемость вашего кода.

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

← К списку