При настройке автоматического обмена данными в распределенной информационной базе (РИБ) по расписанию администраторы и разработчики нередко сталкиваются с ошибкой: «Ошибка при вызове метода контекста (ЗаписатьИзменения): Конфликт блокировок при выполнении транзакции: Превышено максимальное время ожидания предоставления блокировки» (или ее англоязычным аналогом: Lock conflict during the transaction: Maximum idle time for lock access has been exceeded due to the wait for the session). При этом ручной обмен может успешно отрабатывать, а регламентные задания приводят к блокировкам в СУБД, которые не снимаются даже перезапуском сеансов пользователей.
Разберем детально причины возникновения этой ошибки в связке 1С:Предприятие + PostgreSQL + Linux и пошагово рассмотрим способы устранения проблемы.
Проанализируем механику работы обмена данными в 1С. Метод ЗаписатьИзменения() открывает транзакцию и считывает накопленные записи из служебных таблиц регистрации изменений (_ChangeRec). В процессе работы могут возникать следующие коллизии:
8.3.9) присутствовали ошибки менеджера блокировок и механизмов управления пулом соединений к PostgreSQL на Linux, из-за которых сессии СУБД зависали и удерживали транзакцию открытой.idle in transaction: Если фоновое задание прерывается аварийно или соединение между сервером 1С (rphost) и PostgreSQL разрывается некорректно, процесс в PostgreSQL остается в состоянии ожидания с наложенными эксклюзивными блокировками на таблицы изменений.Если вы используете релизы платформы 8.3.9 (например, 8.3.9.2170 или 8.3.9.2033) в связке с PostgreSQL на Linux, основной причиной блокировок является баг платформы в обработке транзакций СУБД.
Для устранения проблемы выполним обновление платформы на более стабильные старшие релизы (например, 8.3.10, 8.3.12 и новее) либо произведем откат на стабильную ветку 8.3.8 (например, 8.3.8.1652). На практике смена проблемного релиза 8.3.9 полностью снимает ложные зависания при вызове метода ЗаписатьИзменения().
Выясним, какие процессы блокируют таблицы на стороне базы данных. Подключимся к СУБД через консоль psql или pgAdmin и выполним запрос для поиска сессий, находящихся в транзакции без активности:
SELECT pid, usename, client_addr, state, query, age(clock_timestamp(), query_start)
FROM pg_stat_activity
WHERE state = 'idle in transaction';
Если в выводе запроса присутствуют длительно висящие процессы, снимем блокирующий процесс по его идентификатору (PID):
SELECT pg_terminate_backend(pid);
Чтобы СУБД автоматически сбрасывала брошенные транзакции и не копила взаимные блокировки, настроим конфигурационный файл postgresql.conf:
idle_in_transaction_session_timeout = 600000 — устанавливает автоматическое завершение сессий, зависших в транзакции более чем на 10 минут.lock_timeout = 60000 — ограничивает максимальное время ожидания получения блокировки.max_locks_per_transaction = 256 — увеличивает лимит табличных блокировок для сложных операций РИБ.После изменения параметров выполним перезагрузку конфигурации PostgreSQL командой SELECT pg_reload_conf(); или перезапустим службу СУБД.
Если блокировки продолжают возникать, настроим технологический журнал платформы для детального выявления виновника конфликта. Разместим в каталоге настроек сервера 1С файл logcfg.xml со следующим содержимым:
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="/var/log/1c/logs" history="24">
<event>
<eq property="name" value="TLOCK"/>
</event>
<event>
<eq property="name" value="TTIMEOUT"/>
</event>
<event>
<eq property="name" value="TDEADLOCK"/>
</event>
<property name="all"/>
</log>
</config>
События TLOCK, TTIMEOUT и TDEADLOCK покажут точный текст транзакции, контекст выполнения в конфигурации 1С и номера сеансов, которые удерживают ресурс и не дают выполниться записи данных.
Для предотвращения конфликтов при работе по расписанию настроим параметры запуска регламентных задач в конфигурации:
ПланыОбмена.УдалитьРегистрациюИзменений().