Почему не записывается регистр сведений из фонового задания в 1С 8.3?

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

Каждый разработчик 1С рано или поздно сталкивается с мистическим поведением платформы: код в фоновом или регламентном задании отрабатывает абсолютно корректно, отладчик показывает успешное заполнение всех свойств, блок Попытка...Исключение не фиксирует никаких ошибок, а в Журнал регистрации пишется заветное «ОК». Однако при открытии информационной базы в режиме «Предприятие» мы обнаруживаем, что данные в регистре сведений остались прежними.

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

Исходная ситуация: как выглядит проблема

Рассмотрим типичный пример кода, который вызывается в общем привилегированном модуле из регламентного задания. Задача процедуры предельно проста — обновить статус документа в независимом регистре сведений:


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

При интерактивном запуске под полными правами данный код отрабатывает без нареканий. Однако при выполнении в фоновом задании происходит странное: в Журнале регистрации мы видим событие со статусом «ОК», отладчик на сервере без проблем проходит строку НаборЗаписей.Записать(), но физически в базе данных запись не меняется.

Выясним истинные причины такого поведения и рассмотрим, как их устранить.

Причина 1. Распределение прав и свойство конфигурации «Основные роли»

Когда регламентное задание запускается на сервере 1С, платформа создает для него отдельный фоновый сеанс. Если у регламентного задания в свойствах (в консоли заданий или в коде инициализации) не указан конкретный пользователь, то платформа определяет права этого сеанса по свойству конфигурации «Основные роли» (Default Roles).

Здесь кроется важный нюанс:

  1. Если свойство «Основные роли» в корне конфигурации заполнено (туда обычно включают базовые роли для запуска тонкого клиента), фоновое задание запустится только с этими правами. Если у этих ролей нет прав на запись в целевой регистр сведений, СУБД заблокирует транзакцию записи.
  2. Если свойство «Основные роли» в конфигурации вообще не заполнено, фоновое задание без указанного пользователя выполнится в привилегированном режиме с полными правами.
  3. Если фоновое задание запускается программно через метод ФоновыеЗадания.Выполнить(), оно наследует контекст и права того пользователя, который его инициировал. Если у интерактивного пользователя нет прав на этот регистр, то и фоновое задание не сможет выполнить запись.

Причина 2. Ограничения привилегированного режима и «Безопасный режим»

Разработчики часто надеются на то, что код выполняется в общем модуле с установленным флагом «Привилегированный». Однако привилегированный режим может быть проигнорирован платформой в следующих случаях:

Причина 3. Почему блок «Попытка...Исключение» не ловит ошибку?

Многих сбивает с толку тот факт, что запись в Журнал регистрации возвращает «ОК», то есть блок Исключение не срабатывает. Это происходит по следующим причинам:

  1. Откат внешней транзакции: Метод НаборЗаписей.Записать() выполняется успешно в рамках локального кода. Но если вся процедура была вызвана внутри другой, более крупной транзакции, которая впоследствии завершилась ошибкой или была явно отменена платформой на выходе из фонового задания, СУБД выполнит полный откат (rollback). При этом Журнал регистрации пишется вне транзакционной модели базы данных, поэтому запись «ОК» в нем благополучно остается.
  2. Механизм RLS (ограничение прав на уровне записей): При использовании RLS платформа может вести себя специфически. В некоторых случаях при попытке записи данных, не соответствующих условиям RLS для текущего сеанса фонового задания, ошибка не вызывается мгновенно на строке Записать(). Ограничение может отработать «тихо», просто не зафиксировав изменения в СУБД, либо вызвать откат всей транзакции на этапе ее фиксации (коммита), который происходит уже за рамками блока Попытка...Исключение конкретной процедуры.
  3. Подписки на события: Ошибка или отмена записи могли тихо происходить в подписках на события «ПередЗаписью» или «ПриЗаписи» этого регистра сведений. Если внутри подписки стоит условие, которое по-разному отрабатывает для обычного пользователя и для фонового процесса (например, обращение к неинициализированным параметрам сеанса), запись может молча блокироваться.

Как решить проблему? Разбираем варианты

Для гарантированного решения проблемы рекомендуется применить один из следующих подходов в зависимости от архитектуры вашей базы данных.

Решение 1. Явное использование привилегированного режима в коде

Самый надежный способ обойти ограничения прав «Основных ролей» фонового задания (если не используется безопасный режим БСП) — это явное переключение в привилегированный режим непосредственно перед записью в регистр:


Процедура ЗаписатьРС(СтруктураДанных) Экспорт
    
    // Устанавливаем привилегированный режим для обхода ограничений ролей
    УстановитьПривилегированныйРежим(Истина);
    
    НаборЗаписей = РегистрыСведений.ДокументыКОтправке.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Документ.Установить(СтруктураДанных.Документ);
    
    // Записывать = Истина использовать не нужно, это свойство только для документов
    НаборЗаписей.Добавить();
    НаборЗаписей[0].Документ = СтруктураДанных.Документ;
    НаборЗаписей[0].Статус = СтруктураДанных.Статус;
    
    НаборЗаписей.Записать();
    
    // Возвращаем обычный режим работы сеанса
    УстановитьПривилегированныйРежим(Ложь);
    
КонецПроцедуры

Решение 2. Корректировка прав «Основных ролей» конфигурации

Если в вашей конфигурации определены основные роли (свойство конфигурации «Основные роли»), убедитесь, что у тех ролей, которые туда входят, есть явные права на Чтение, Просмотр, Изменение и Запись для проблемного регистра сведений.

Если фоновое задание запускается под конкретным пользователем, проверьте в режиме «1С:Предприятие», назначены ли этому пользователю роли, позволяющие вносить изменения в данный регистр.

Решение 3. Проверка транзакционности

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


Если ТранзакцияАктивна() Тогда
    ЗаписьЖурналаРегистрации("ОтладкаТранзакции", 
        УровеньЖурналаРегистрации.Предупреждение,,, "Код выполняется внутри транзакции!");
КонецЕсли;

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

← На главную