В высоконагруженных системах 1С классический подход «отправил запрос — получил ответ — записал в справочник» часто приводит к конфликтам блокировок. Когда база интенсивно используется, попытка создания элемента справочника в транзакции, ожидающей ответа от внешнего API, может вызвать таймауты и ошибки, а повторные попытки отправки приводят к дублированию данных. Разберем, как построить надежную архитектуру обмена.
Основная проблема заключается в том, что запись в справочник — это тяжелая операция, которая накладывает блокировки на таблицы. Если ваш код отправляет запрос к сайту синхронно (ожидая ответа), транзакция может удерживаться слишком долго. В условиях конкурентного доступа, когда другие пользователи или процессы пытаются работать с тем же справочником, возникают взаимные блокировки. Попытка обернуть всё в Попытка...Исключение — это лишь борьба с симптомами, которая не решает архитектурную проблему.
Самым эффективным способом борьбы с блокировками является асинхронная модель. Вместо того чтобы пытаться записать данные в справочник немедленно, мы разделим процесс на два независимых этапа с помощью РегистрСведений.
ОчередьОбменаССайтим. В этой записи фиксируются исходные данные, необходимые для отправки, и устанавливается статус, например, КОтправке.КОтправке, выполняет HTTP-запрос к сайту, получает ответ (идентификатор) и только после этого вносит изменения в справочник.Этот подход позволяет полностью исключить блокировки справочника на этапе ожидания ответа от сервера, так как сетевой запрос происходит вне транзакции записи справочника.
Рассмотрим структуру РегистрСведений. Создайте регистр с периодичностью «В пределах секунды» или без периодичности, добавив в него измерения и ресурсы:
ОбъектСсылка (тип СправочникСсылка)ДанныеДляОтправки (тип ХранилищеЗначения)Статус (тип ПеречислениеСсылка.СтатусыОбмена)ОтветСайта (тип Строка)Теперь процесс отправки выглядит следующим образом:
// Пример логики регламентного задания
Выборка = РегистрыСведений.ОчередьОбменаССайтим.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.Статус = Перечисления.СтатусыОбмена.КОтправке Тогда
Результат = ОтправитьНаСайт(Выборка.ДанныеДляОтправки);
Если Результат.Успешно Тогда
// Запись в справочник после получения ответа
Объект = Выборка.ОбъектСсылка.ПолучитьОбъект();
Объект.ИдентификаторСайта = Результат.ИД;
Объект.Записать();
// Удаляем из очереди или меняем статус
НаборЗаписей = РегистрыСведений.ОчередьОбменаССайтим.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ОбъектСсылка.Установить(Выборка.ОбъектСсылка);
НаборЗаписей.Записать(Истина);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Рассмотрим подробнее, почему использование регистра сведений снимает нагрузку:
Если в определенных сценариях вам все же необходимо записывать данные в рамках одной транзакции, используйте объект БлокировкаДанных. Он позволяет явно указать системе, какие данные вы планируете изменять, еще до начала процесса записи:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Номенклатура");
ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаОбъект);
Блокировка.Заблокировать();
Использование этого механизма позволяет системе заранее «зарезервировать» объект, предотвращая попытки других транзакций модифицировать его одновременно с вами. Однако помните, что асинхронная очередь остается лучшей практикой для высоконагруженных систем 1С, так как она переносит сетевые операции за пределы критических секций кода.
Проанализируйте вашу текущую архитектуру: если количество пользователей и интенсивность обменов растет, не бойтесь вводить промежуточные хранилища в виде РегистрСведений. Это стандартный и самый надежный путь профессиональной разработки в 1С.