Разберем распространенную ситуацию в розничной торговле: в подчиненном узле распределенной информационной базы (РИБ) под управлением «1С:Управление торговлей 10.3» настроен автоматический обмен данными. Кассир пробивает документ ЧекККМ, но в момент проведения система выдает ошибку о конфликте блокировок или просто зависает. Выясним причину такого поведения и подробно рассмотрим способы устранения проблемы.
Проанализируем архитектурные особенности работы файловой базы (формат .1CD). В отличие от клиент-серверного варианта (SQL), файловый движок платформы 1С не поддерживает блокировки на уровне отдельных строк (Row-Level Locking). Любая транзакция записи монопольно блокирует физическую таблицу целиком.
В конфигурации «Управление торговлей 10.3» используется автоматический режим управления блокировками данных. При стандартной загрузке пакета РИБ все данные часто записываются в рамках одной длинной транзакции или крупными порциями. В этот момент блокируются ключевые таблицы: справочники цен, номенклатуры, регистры накопления остатков и партий. Когда продавец пытается провести ЧекККМ, документу требуется записать движения в эти же регистры, что мгновенно приводит к конфликту блокировок.
Самый эффективный и проверенный на практике способ — разделить процесс загрузки на множество коротких транзакций. Если пакет данных записывается не целиком, а небольшими порциями (вплоть до одного объекта на одну транзакцию), между ними образуются окна, в которые система успевает вклинить проведение чека кассира.
Рассмотрим, как это реализовать:
При такой настройке общая длительность загрузки пакета РИБ может немного увеличиться, однако кассир получает возможность непрерывно оформлять продажи без аварийных сбоев.
Даже при дроблении транзакций кассир может случайно попасть ровно в тот момент, когда фиксируется один из объектов обмена. Чтобы исключить выдачу ошибки на экран кассира, доработаем обработчик проведения чека, добавив циклический перехват исключений с задержкой.
Посмотрим на пример реализации в коде формы или модуля документа:
КоличествоПопыток = 5;
УспешноЗаписан = Ложь;
Для НомерПопытки = 1 По КоличествоПопыток Цикл
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
УспешноЗаписан = Истина;
Прервать;
Исключение
Если НомерПопытки < КоличествоПопыток Тогда
// Делаем небольшую паузу перед повтором, чтобы транзакция обмена успела зафиксироваться
ТекущееВремя = ТекущаяДата();
Пока (ТекущаяДата() - ТекущееВремя) < 1 Цикл
// Ожидание 1 секунды
КонецЦикла;
Иначе
ВызватьИсключение "Не удалось провести чек из-за занятости таблиц базы данных. Повторите попытку через несколько секунд.";
КонецЕсли;
КонецПопытки;
КонецЦикла;
В этом сценарии платформа делает до 5 попыток провести чек с секундным интервалом, освобождая продавца от необходимости вручную нажимать кнопку повторно.
Если требуется точно знать, выполняется ли в текущую секунду загрузка сообщения, рассмотрим несколько программных способов определения активности обмена:
ПолучитьСоединенияИнформационнойБазы(). Если автоматический обмен запускается под выделенным служебным пользователем, перед проведением документа проверяем массив активных сеансов. Если служебный пользователь присутствует в списке, можно предупредить кассира или подождать завершения его работы.СостоянияОбменовДанными. В типовой подсистеме обмена УТ 10.3 начало и окончание загрузки фиксируются в этом регистре. Запросом по узлу обмена с отбором по пустой дате окончания можно определить активную фазу фонового процесса.Заблокировать(). В коде кассира перед записью проверяется доступность этого элемента. При разрыве соединения блокировка автоматически снимается платформой.Проанализируем также варианты оптимизации самого регламента обменов, не требующие глубоких изменений в конфигурации: