Как отловить и записать взаимоблокировки при проведении документов в Журнал регистрации

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

В процессе работы высоконагруженных систем на базе 1С и Microsoft SQL Server часто возникает неприятная ситуация — взаимоблокировка ресурсов (deadlock). Пользователь видит пугающее сообщение об ошибке с кодом 1205, транзакция откатывается, и данные не сохраняются. В этой статье мы подробно разберем, как локализовать эту проблему, зафиксировать её в Журнале регистрации для последующего анализа и какие превентивные меры можно предпринять.

Суть проблемы: почему возникает ошибка 1205

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

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

Решение 1: Явный вызов записи движений в блоке Попытка-Исключение

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

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


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

    // Попробуем записать движения явно, чтобы отловить deadlock
    Попытка
        Движения.ОтгрузкаТоваров.Записать();
    Исключение
        // Получаем подробное описание ошибки для администратора
        ТекстОшибки = ИнформацияОбОшибке().Описание;
        
        // Проверяем, является ли это ошибкой блокировки SQL
        Если Найти(ТекстОшибки, "1205") > 0 Или Найти(ТекстОшибки, "Конфликт блокировок") > 0 Тогда
            
            ЗаписьЖурналаРегистрации(
                "Транзакция.Взаимоблокировка",
                УровеньЖурналаРегистрации.Ошибка,
                ЭтотОбъект.Метаданные(),
                ЭтотОбъект.Ссылка,
                "Произошла взаимоблокировка при записи регистра ОтгрузкаТоваров. Текст ошибки: " + ТекстОшибки
            );
            
        КонецЕсли;
        
        // Устанавливаем отказ и пробрасываем исключение дальше для отката всей транзакции
        Отказ = Истина;
        ВызватьИсключение; 
    КонецПопытки;

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

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

Решение 2: Анализ через Технологический журнал

Если мы не хотим менять программный код каждого документа, разберем альтернативный метод — использование Технологического журнала (ТЖ). Это мощный инструмент, который фиксирует события на уровне платформы.

Для отслеживания взаимоблокировок нам необходимо создать файл logcfg.xml в каталоге настроек 1С (обычно это C:\Program Files\1cv8\conf) со следующим содержимым:


<config xmlns="http://v8.1c.ru/7.4/config/logcfg">
  <log location="C:\LOGS\DEADLOCKS" history="168">
    <event>
      <eq property="Name" value="DBMSSQL"/>
      <like property="Context" value=".*Deadlock.*"/>
    </event>
    <property name="All"/>
  </log>
</config>

После настройки ТЖ платформа начнет записывать все события СУБД, связанные с конфликтами блокировок. Проанализировав эти файлы, мы сможем увидеть не только факт ошибки, но и конкретный SQL-запрос, который к ней привел.

Анализ причин и способы предотвращения

Выясним причину, почему возникают такие ситуации. Как показала практика (сообщение 8 темы), часто конфликты провоцируются массовыми операциями, например, при запуске Групповой обработки справочников и документов одновременно с текущей работой пользователей (ввод чеков ККМ или реализаций).

Посмотрим, что можно сделать для снижения вероятности взаимоблокировок:

  1. Сортировка табличной части. Перед записью движений в регистр всегда сортируйте строки по ключевым полям (Номенклатура, Склад). Если два документа записывают товары А и Б в разном порядке (один А-Б, другой Б-А), они гарантированно встретятся на блокировках. Если оба пишут в порядке А-Б, второй просто подождет завершения первого.
  2. Управляемые блокировки. Переведите конфигурацию (или конкретные объекты) в режим управляемых блокировок. Это позволит 1С выстраивать очередь запросов на уровне приложения, не доводя дело до жестких конфликтов на уровне SQL Server. Используйте объект БлокировкаДанных перед началом записи.
  3. Минимизация транзакций. Проанализируйте код. Постарайтесь вынести все тяжелые расчеты и запросы за пределы транзакции (до вызова Записать() или начала проведения). Чем короче транзакция, тем меньше шансов на конфликт.
  4. Настройка SQL Server. Убедитесь, что для базы данных включен параметр Read Committed Snapshot Isolation (RCSI). Это позволит операциям чтения не блокировать операции записи, что существенно разгружает систему.

Использование SQL Server Profiler

Если программных средств 1С недостаточно, воспользуемся инструментами СУБД. Проанализируем ситуацию с помощью SQL Server Profiler. Для этого нужно выбрать шаблон события Deadlock graph. В момент возникновения ошибки SQL Server сформирует графическую схему, на которой будет видно:

Подведем итог: взаимоблокировки — это сигнал о том, что ресурсы системы распределяются неоптимально. Комбинируя программный перехват ошибки в 1С для оперативного оповещения и инструменты глубокого анализа (ТЖ, SQL Profiler), мы сможем не только фиксировать статистику, но и планомерно устранять узкие места в коде конфигурации.

← На главную