Как исправить ошибку «Ошибка снятия блокировки объекта. Объект не заблокирован» при отмене проведения документа в 1С?

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

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

Проанализируем контекст возникновения проблемы

Рассмотрим типичный сценарий. В самописной или сильно модифицированной конфигурации существует подписка на событие ПередЗаписью для ряда документов. Задача подписки — проверять соответствие периода документа текущему открытому периоду (например, через константу). Если пользователь пытается изменить документ «задним числом», система должна выдать предупреждение и прервать операцию, установив параметр Отказ = Истина.

Типичный код такой подписки выглядит следующим образом:


Процедура ПодпискаПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
    Если Источник.УчетныйМесяц <> Константы.ТекущийПериод.Получить() Тогда
        ТекстСообщения = "Запрещено перепроведение документов за пределами периода: " + 
                         Формат(Константы.ТекущийПериод.Получить(), "ДФ=MM.yyyy");
        Сообщить(ТекстСообщения);
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

На платформе 8.1 данный код работает безупречно: при попытке записи или проведения документа старого периода транзакция откатывается, и пользователь видит сообщение. Однако на платформе 8.2 (особенно на релизах 8.2.19.х) при попытке отменить проведение документа возникает критическая ошибка блокировки. При этом пометка на удаление может проходить успешно, что вносит дополнительную путаницу в диагностику.

Выясним причины изменения поведения платформы

Разберем по шагам, что происходит в недрах платформы 8.2 при отмене проведения документа. Основное различие между 8.1 и 8.2 заключается в механизмах объектных блокировок и взаимодействия клиентской части с сервером приложений.

  1. Пессимистическая блокировка: Когда пользователь инициирует отмену проведения из формы или списка, платформа устанавливает пессимистическую блокировку на объект, чтобы гарантировать, что никто другой не изменит его в процессе отката транзакции.
  2. Транзакционный механизм: В платформе 8.2 цепочка событий при отмене проведения стала более жестко контролируемой. Когда в процедуре ПередЗаписью срабатывает Отказ = Истина, платформа немедленно инициирует откат транзакции.
  3. Конфликт менеджера блокировок: В определенных релизах платформы возникает ситуация, когда принудительный отказ от записи приводит к тому, что менеджер блокировок на сервере уже считает объект свободным (так как транзакция прервана), но клиентская часть платформы все еще пытается программно выполнить команду «разблокировать». Поскольку блокировка в кэше сервера уже аннулирована из-за отката, возникает сабж: «Ошибка снятия блокировки объекта. Объект не заблокирован».

Таким образом, мы видим внутреннее противоречие в менеджере блокировок, вызванное тем, что объект «завис» в памяти в неопределенном состоянии после прерывания процесса записи.

Решение №1: Принудительное снятие блокировки (быстрый способ)

Как показывает практика и обсуждения на технических форумах, наиболее быстрым (хотя и не самым «красивым») способом устранить ошибку является принудительный вызов метода Разблокировать() у источника события в случае отказа. Рассмотрим, как изменить код подписки:


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

Важное замечание: Метод Источник.Разблокировать() принудительно очищает таблицу объектных блокировок для данного сеанса. Это позволяет платформе «успокоиться» и вернуть управление пользователю без вылета в критическую ошибку. Однако стоит помнить, что это может привести к тому, что объект станет доступен для редактирования в другом сеансе чуть раньше, чем планировалось логикой платформы.

Решение №2: Проверка режима записи

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

Чтобы избежать коллизий с блокировками, мы можем добавить проверку параметра РежимЗаписи. Это позволит более гибко управлять логикой отказа:


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

    Если Источник.УчетныйМесяц <> Константы.ТекущийПериод.Получить() Тогда
        Отказ = Истина;
        Сообщить("Запрещено!");
    КонецЕсли;
КонецПроцедуры

Рекомендации по стабильной работе в 1С 8.2 и 8.3

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

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

← На главную