Почему возникает конфликт блокировок при проведении документов в разные периоды?

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

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

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

Причина №1: Неявные управляемые блокировки при записи данных

Основной источник недопонимания — это поведение системы при записи данных без явной установки блокировок. Многие разработчики полагают, что если в коде проведения документа не написан блок БлокировкаДанных = Новый БлокировкаДанных, то никаких блокировок не будет. Это не так.

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

Рассмотрим ситуацию из вопроса:

  1. Первый документ (назовем его "Документ А") в своей транзакции устанавливает явную исключительную блокировку на регистр по диапазону дат (прошлый месяц) и по определенной организации. Он останавливается на точке останова, удерживая эту блокировку.
  2. Второй документ ("Документ Б") начинает проведение в другой транзакции. Он не устанавливает явных блокировок. В какой-то момент он формирует набор записей для того же регистра и вызывает метод Записать().
  3. В момент вызова Записать() платформа пытается установить неявную блокировку на записываемые данные по всем измерениям регистра.

Если значения каких-либо измерений у "Документа А" и "Документа Б" совпадают (например, 'Организация', 'Склад', 'Номенклатура'), возникает конфликт. Транзакция "Документа Б" будет ждать освобождения ресурса. Если "Документ А" не снимет свою блокировку в течение таймаута (по умолчанию 20 секунд), то транзакция "Документа Б" аварийно завершится с ошибкой.

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

Причина №2: Влияние итогов регистра накопления

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

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

Посмотрим на пример:

Пусть у нас есть регистр накопления "Продажи" с измерениями "Организация", "Контрагент", "Номенклатура" и ресурсом "Сумма". Итоги рассчитываются по всем измерениям.

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

Таймаут или взаимоблокировка (Deadlock)?

В обсуждении возник спор о терминах. Важно четко их различать для правильной диагностики.

Правильное определение типа проблемы — первый шаг к ее решению. В нашем случае речь идет о таймауте.

Как диагностировать проблему: используем Технологический журнал (ТЖ)

Чтобы точно определить, по каким данным происходит конфликт, самым эффективным инструментом является Технологический журнал (ТЖ). Он позволяет увидеть "под капотом", какие именно ресурсы и по каким полям блокируются.

Разберем по шагам, как его использовать для нашей задачи:

  1. Настройте ТЖ. Вам нужно создать файл logcfg.xml в папке conf сервера 1С и включить в нем сбор событий, связанных с блокировками. Минимально необходимая настройка:
    
    <?xml version="1.0" encoding="UTF-8"?>
    <config xmlns="http://v8.1c.ru/v8/tech-log">
      <log location="C:\1C\Logs" history="4">
        <event>
          <eq property="name" value="TLOCK"/>
        </event>
        <event>
          <eq property="name" value="TDEADLOCK"/>
        </event>
        <property name="all"/>
      </log>
    </config>
    

    Не забудьте перезапустить службу агента сервера 1С, чтобы настройки применились.

  2. Воспроизведите проблему. Запустите оба документа так, чтобы возникла ошибка таймаута ожидания блокировки.
  3. Проанализируйте логи. Откройте файлы логов, созданные в папке C:\1C\Logs. Вам нужно найти событие TLOCK, которое длилось около 20 секунд. В логе оно будет выглядеть примерно так:
    
    25:35.312015-20000024,TLOCK,1,process=rphost,p:processName=... t:connectID=123, ... WaitConnections=124, ...
    

    Ключевой параметр здесь — duration, который для таймаута будет равен 20000000 микросекунд (20 секунд). t:connectID=123 — это номер соединения, которое ждало, а WaitConnections=124 — номер соединения, которое удерживало блокировку.

  4. Найдите источник конфликта. В описании события TLOCK будет указана область блокировки (Regions) и значения полей (Descr), по которым произошло пересечение. Вы увидите, что, например, оба сеанса пытались заблокировать одну и ту же запись с одинаковым значением поля "Организация", что и стало причиной конфликта. Это даст вам точный и неоспоримый ответ на вопрос, где именно пересеклись ваши транзакции.

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

← На главную