При активной работе пользователей в программах 1С:Комплексная автоматизация 2 или 1С:ERP Управление предприятием часто возникает неприятная ситуация: во время проведения обычных документов (таких как «Заказ клиента», «Реализация товаров и услуг», «Перемещение товаров» или при закрытии месяца) система аварийно завершает работу. На экран выводится критическая ошибка: «Конфликт блокировок при выполнении транзакции: Превышено максимальное время ожидания предоставления блокировки» с указанием на константу НомерЗаданияКФормированиюДвиженийПоНДС.
В этой статье мы подробно проанализируем, почему возникает данная техническая проблема, разберем архитектурные причины конфликта на уровне СУБД, а также рассмотрим по шагам все возможные способы её исправления как на уровне администрирования, так и на уровне разработки.
Давайте разберем внутреннюю кухню распределения задач в ERP-решениях 1С. Константа НомерЗаданияКФормированиюДвиженийПоНДС выполняет роль глобального координатора или счетчика пакетов данных. Когда запускается процедура «Формирование движений по НДС» (особенно в многопоточном режиме при закрытии месяца), система делит весь массив документов на порции. Чтобы параллельные фоновые задания не обрабатывали одни и те же транзакции, система нумерует эти порции (задания), последовательно считывая и увеличивая значение этой константы.
Проблема кроется в следующих факторах:
Это классический пример нарушения стандартов разработки Фирмы 1С. Согласно официальной «Системе стандартов и методик разработки конфигураций», использовать константы для хранения оперативно меняющихся данных (счетчиков, очередей задач) категорически запрещено. Для этих целей должны применяться регистры сведений с включенным режимом управляемых блокировок.
Перед тем как приступать к исправлению, выясним, как оперативно локализовать виновника блокировки в работающей базе данных. Проанализируем несколько доступных инструментов:
Способ 1: Использование консоли администрирования кластера серверов 1С
В утилите администрирования перейдите в ветку вашего информационного склада, откройте список «Сеансы». Добавьте в список колонки «Заблокировано СУБД» и «Захватил СУБД». Во время возникновения ошибки вы сможете увидеть, какой конкретно сеанс держит эксклюзивную блокировку на таблицу констант.
Способ 2: Настройка Технологического журнала (ТЖ)
Для детального логирования дедлоков и таймаутов мы можем настроить сбор событий DBMSSQL и TLOCK. Создайте файл logcfg.xml в каталоге конфигурирования платформы со следующим содержимым:
<config xmlns="http://v8.1c.ru/v8/tech-journal">
<log location="C:\v8logs\locks" history="24">
<event>
<eq property="Name" value="TLOCK"/>
</event>
<event>
<eq property="Name" value="TTIMEOUT"/>
</event>
<property name="all"/>
</log>
</config>
Анализ полученных логов позволит с точностью до секунды и строки кода определить, какая процедура инициировала длительную транзакцию.
Разберем по шагам практические методы решения проблемы, начиная с простых административных настроек и заканчивая программным обходом.
В конфигурациях ERP и КА предусмотрена специальная настройка, регулирующая размер пакетов при расчете НДС. Перейдите в раздел администрирования закрытия месяца и найдите параметры этапа «Формирование движений по НДС». По умолчанию параметр «Количество заданий для порционного расчета НДС» равен 100. Изменение этого значения в меньшую сторону снизит размер транзакций и нагрузку на СУБД, а увеличение — сократит общее число транзакций записи в константу. Экспериментальным путем подберите оптимальный баланс под ваше серверное оборудование.
Очень часто фоновые задания генерации движений НДС запускаются из-за того, что пользователи случайно перепроводят или изменяют документы в прошлых (уже закрытых) периодах. Настоятельно рекомендуем включить жесткую «Дату запрета изменения данных» для всех пользователей, кроме администраторов. Это избавит систему от избыточной генерации фоновых задач по историческим данным и разгрузит общую константу-координатор.
Параллельный запуск расчета себестоимости, закрытия месяца и активного ввода первичных документов (отгрузок, оплат, возвратов) практически гарантированно приведет к дедлокам на стыке констант и регистров сведений. Настройте расписание регламентных заданий так, чтобы все ресурсоемкие операции выполнялись ночью или в периоды минимальной активности пользователей.
Если проблему нужно устранить немедленно, чтобы пользователи могли продолжить работу, мы можем временно увеличить системный таймаут ожидания блокировок с стандартных 20 до 40–60 секунд. Сделать это можно в Конфигураторе через меню Администрирование — Параметры информационной базы — Время ожидания блокировки данных. Это даст процессам дополнительное время дождаться своей очереди, хотя и может субъективно замедлить отклик интерфейса при высокой нагрузке.
Так как данная проблема имеет массовый характер и признана разработчиками фирмы 1С как несовершенство архитектуры, периодически выпускаются официальные патчи (исправления). В последних релизах ERP и КА разработчики постепенно уходят от хранения оперативных очередей в константах. Регулярно проверяйте и устанавливайте обновления конфигурации и платформы.
Если вы работаете на нетиповой или сильно измененной конфигурации и имеете возможность вносить изменения в код, то лучшим решением будет отказ от константы. Перенесите хранение счетчика заданий в непериодический регистр сведений (например, создав регистр ОчередьЗаданийНДС) с включенным режимом управляемых блокировок.
Рассмотрим пример кода, как безопасно инкрементировать значение счетчика в транзакции с использованием механизма управляемых блокировок платформы 1С:
НачатьТранзакцию();
Попытка
// Инициализируем управляемую блокировку для нашего регистра-счетчика
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СчетчикиЗаданийНДС");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
// Блокируем конкретный ключ (например, имя счетчика)
ЭлементБлокировки.УстановитьЗначение("ИмяСчетчика", "ФормированиеДвиженийПоНДС");
Блокировка.Заблокировать();
// Читаем текущее значение из регистра
Отбор = Новый Структура("ИмяСчетчика", "ФормированиеДвиженийПоНДС");
ТекущееЗначение = РегистрыСведений.СчетчикиЗаданийНДС.ПолучитьПоследнее(,, Отбор).Значение;
// Записываем инкрементированное значение
МенеджерЗаписи = РегистрыСведений.СчетчикиЗаданийНДС.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИмяСчетчика = "ФормированиеДвиженийПоНДС";
МенеджерЗаписи.Значение = ТекущееЗначение + 1;
МенеджерЗаписи.Записать(Истина);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение "Не удалось выделить номер задания из-за конфликта блокировок: " + ОписаниеОшибки();
КонецПопытки;
Использование регистра сведений с точечной блокировкой по измерению (в отличие от блокировки всей таблицы констант) позволяет значительно повысить параллельность работы пользователей и полностью избавиться от зависаний системы при формировании движений по НДС.