При совместной работе распределенных информационных баз (РИБ) в связке «1С:Управление торговлей — 1С:Розница» администраторы и программисты часто сталкиваются с критической проблемой. В момент проведения фонового автообмена кассир на торговой точке пытается пробить чек. Из-за пересечения транзакций база данных блокирует таблицы. В результате на фискальном регистраторе чек успешно печатается, а в программе «1С» транзакция откатывается из-за ошибки совместного доступа. Чек остается в статусе «Не провелся», выручка в программе не отражается, а товар не списывается.
В этой статье мы подробно разберем, как решить проблему взаимных блокировок при синхронизации, как настроить время ожидания блокировок СУБД, а также как реализовать программный механизм оповещения кассира в рабочем месте кассира (РМК).
В процессе обмена данными система «1С:Предприятие» производит запись большого объема объектов (документов, справочников, регистров сведений). При записи любого объекта СУБД накладывает исключительную блокировку на таблицы базы данных, чтобы гарантировать целостность транзакции. Если в этот же момент кассир проводит чек, программе требуется обновить таблицы остатков товаров и взаиморасчетов, которые уже заблокированы процессом обмена.
По умолчанию в платформе «1С:Предприятие» время ожидания блокировки данных составляет 20 секунд. Если транзакция загрузки пакета обмена длится дольше (например, 40 секунд), то по истечении 20 секунд касса «вылетает» с ошибкой СУБД, хотя команда на фискальный аппарат уже могла уйти.
Самый быстрый административный способ решить проблему — дать кассовой транзакции больше времени «дождаться» окончания записи пакета обмена. Рассмотрим, как это сделать по шагам:
120.Если мы установим 120 секунд (или даже 5 минут), то при начале обмена чек у кассира не выдаст ошибку сразу. Программа просто «задумается» на время записи пакета обмена, а как только транзакция синхронизации завершится, чек успешно проведется без сбоев.
Чтобы кассир не испытывал дискомфорта от «зависания» интерфейса во время оплаты, мы можем реализовать механизм программных флагов-семафоров. Рассмотрим алгоритм его работы:
Создадим простой регистр сведений или будем использовать константу, например, ИдетОбменДанными со значением типа Булево. Перед началом загрузки пакета РИБ регламентное задание устанавливает этот флаг в значение Истина, а после завершения — в Ложь.
В модуле формы РМК перед началом выполнения транзакции пробития чека добавим проверку этого флага:
// Функция проверки активности фонового обмена данными
Функция ПроверитьАктивностьОбмена() Экспорт
Возврат Константы.ИдетОбменДанными.Получить();
КонецФункции
// Обработчик события перед пробитием чека в РМК
&НаКлиенте
Процедура ПередПробитиемЧека(Отказ)
Если ПроверитьАктивностьОбмена() Тогда
Отказ = Истина;
ПоказатьПредупреждение(, "В данный момент идет фоновая синхронизация баз данных. Пожалуйста, подождите 1 минуту.", 10, "Синхронизация");
Возврат;
КонецЕсли;
КонецПроцедуры
Такой подход полностью исключает физическую возможность одновременного запуска двух конфликтующих транзакций.
Если мы не хотим создавать дополнительные константы, мы можем программно опрашивать состояние регламентных заданий обмена напрямую из клиента 1С с помощью обработчика ожидания.
Разберем пример подключения такого обработчика в форме РМК:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем опрос состояния обмена каждые 15 секунд
ПодключитьОбработчикОжидания("ПроверитьСтатусСинхронизации", 15, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьСтатусСинхронизации()
ВыполняетсяОбмен = ВыяснитьСтатусФоновогоОбменаНаСервере();
Если ВыполняетсяОбмен Тогда
// Делаем кнопку пробития чека недоступной и выводим баннер-предупреждение
Элементы.КнопкаПробитьЧек.Доступность = Ложь;
Элементы.ДекорацияПредупреждениеОбмен.Заголовок = "Внимание: идет фоновый обмен данными!";
Элементы.ДекорацияПредупреждениеОбмен.Видимость = Истина;
Иначе
Элементы.КнопкаПробитьЧек.Доступность = Истина;
Элементы.ДекорацияПредупреждениеОбмен.Видимость = Ложь;
КонецЕсли;
КонецПроцедуры
На сервере код проверки запущенных фоновых заданий обмена будет выглядеть следующим образом:
&НаСервереБезКонтекста
Функция ВыяснитьСтатусФоновогоОбменаНаСервере()
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Состояние", СостояниеФоновогоЗадания.Активно);
// Ищем активные задания по имени нашего регламентного задания обмена
СписокЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(ПараметрыОтбора);
Для Каждого Задание Из СписокЗаданий Цикл
Если Найти(Задание.Наименование, "Выполнить обмен данными") > 0 Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Зачастую блокировки возникают из-за неоптимальных настроек записи данных в правилах обмена. Проанализируем настройки узла распределенной информационной базы:
Количество элементов в транзакции (например, до 50 или 100 объектов). СУБД будет записывать данные небольшими порциями, мгновенно завершая микротранзакции, что даст кассиру «окно» для проведения чека.Зададимся вопросом: действительно ли необходим обмен каждые 30 минут? В розничной торговле оперативные остатки в бэк-офисе (УТ) часто требуются для перемещения товаров между точками.
Если это так, рассмотри альтернативные варианты интеграции:
Если блокировка все же произошла, и чек завис, научим персонал торговой точки действовать по строгому регламенту: