Почему зависает блокировка пустого регистра сведений и как это исправить

Программист IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие 8.3 нередко встречается ситуация, когда стандартный, на первый взгляд, код вызывает «мертвое» зависание системы. Особенно часто это происходит при работе с системными регистрами, такими как РегистрСведений.ТаблицыГруппДоступа. Проанализируем ситуацию: код выполняется в транзакции, регистр абсолютно пуст, но команда Заблокировать() останавливает работу сеанса до истечения времени ожидания. Выясним причины этого поведения и разберем по шагам, как устранить проблему.

Разбор типичной ошибки в коде блокировки

Рассмотрим фрагмент кода, который чаще всего становится причиной обсуждения:


Блокировка = Новый БлокировкаДанных;
Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа");
    
НачатьТранзакцию();
Блокировка.Заблокировать();
// Выполнение операций с регистром
ЗафиксироватьТранзакцию();

Первое, на что стоит обратить внимание — это порядок вызова команд. В обсуждении прозвучало предложение устанавливать блокировку до начала транзакции. Разберем, почему это невозможно. Управляемые блокировки в 1С жестко привязаны к контексту транзакции. Если вызвать метод Заблокировать() вне транзакции, система выдаст ошибку, так как блокировка должна сниматься автоматически при завершении транзакции (фиксации или отмене). Поэтому правильная последовательность всегда: НачатьТранзакцию() -> Заблокировать() -> ЗафиксироватьТранзакцию().

Причина №1: Глобальная блокировка всего ресурса

Проанализируем строку Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"). В данном случае не указано ни одного пространства значений (фильтра). Это означает, что система пытается установить исключительную блокировку на весь регистр целиком.

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

Причина №2: Конфликт с фоновыми заданиями БСП

Регистр ТаблицыГруппДоступа входит в состав подсистемы управления доступом БСП. В типовых конфигурациях (БП, ЗУП, ERP, БП ЖКХ) постоянно работают фоновые задания, такие как:

  1. Обновление прав доступа — актуализирует зависимости прав.
  2. Заполнение данных для ограничения доступа — рассчитывает права на уровне записей (RLS).

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

Причина №3: Проблема «фантомных» сеансов и СУБД

Иногда причина кроется глубже — на уровне кластера или СУБД (MS SQL Server, PostgreSQL). Рассмотрим несколько сценариев:

Пошаговое решение проблемы

Чтобы решить проблему «зависания», выполним следующие действия:

Шаг 1: Остановка регламентных заданий

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

Шаг 2: Проверка активных блокировок

Воспользуемся консолью администрирования кластера 1С. Разберем алгоритм действий:

  1. Откройте консоль администрирования.
  2. Перейдите в раздел «Блокировки».
  3. Найдите ресурс, соответствующий вашему регистру.
  4. Посмотрите колонку «Сеанс», который держит блокировку. Если это не ваш сеанс — вот причина ожидания.

Шаг 3: Использование технологического журнала

Если визуально определить причину не удается, настроим сбор событий Технологического журнала. Нам интересны события TLOCK (установка блокировки) и TTIMEOUT (превышение времени ожидания). Проанализировав файл лога, мы увидим точное имя ресурса и номер сеанса-виновника.

Пример настройки logcfg.xml для поиска виновника:


<event query="e.type == 'TLOCK' | e.type == 'TTIMEOUT'">
    <property name="all"/>
</event>

Шаг 4: Оптимизация кода обновления

Если задача стоит просто очистить регистр, можно рассмотреть альтернативные методы, которые менее требовательны к блокировкам всего ресурса. Однако, если вы используете типовой код из модуля ОбновитьДанныеРегистра(), лучше обеспечить «чистую» среду для его выполнения.

Рассмотрим рекомендации по монопольному доступу. При выполнении критичных обновлений информационной базы полезно устанавливать блокировку установки соединений:

  1. Выгнать всех пользователей.
  2. Установить блокировку новых соединений в консоли кластера.
  3. Запустить процедуру обновления.

Резюме

Зависание на пустом регистре — это классический симптом очереди блокировок. Несмотря на отсутствие записей в таблице, сам объект «РегистрСведений» является разделяемым ресурсом. Основной путь решения — исключение параллельных процессов (фоновых заданий) и проверка наличия зависших транзакций в кластере 1С или СУБД. Помните, что управляемые блокировки эффективны только тогда, когда они накладываются на конкретные измерения, а блокировка «всего регистра» должна применяться крайне осторожно и только в отсутствие других пользователей в системе.

← На главную