Как правильно связать две базы 1С в реальном времени без зависаний и блокировок СУБД?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При автоматизации крупных торговых и производственных предприятий разработчики часто сталкиваются с задачей интеграции нескольких информационных баз 1С. Например, когда менеджеры работают в современной конфигурации 1С:Управление торговлей 11, а основной производственный и складской учет ведется в 1С:Управлении производственным предприятием 1.3 (УПП). Возникает соблазн сделать «красивое» и быстрое решение: при проведении заказа покупателя в УТ 11 мгновенно подключаться к УПП, создавать там аналогичный заказ, проверять остатки, резервировать товар и возвращать результат.

Однако реализация такой схемы «в лоб» через синхронный вызов (особенно через устаревшие COM-технологии) внутри транзакции проведения — это гарантированный способ парализовать работу всей системы. Давайте подробно разберем, почему синхронная интеграция в транзакции является критической архитектурной ошибкой, к каким последствиям она приводит на уровне СУБД, и рассмотрим надежные асинхронные альтернативы, которые успешно применяются в современной практике.

В чем опасность синхронных запросов внутри транзакции проведения?

Давайте проанализируем, что происходит на уровне системы управления базами данных (MS SQL, PostgreSQL), когда пользователь нажимает кнопку «Провести» в документе ЗаказКлиента. Платформа 1С запускает неявную транзакцию СУБД. В этот момент накладываются монопольные и разделяемые блокировки на таблицы регистров, связанные с этим документом (например, остатки товаров, взаиморасчеты, денежные средства).

Если внутри процедуры ОбработкаПроведения мы инициируем внешнее подключение к другой базе (неважно, через V83.COMConnector, Web-сервис или HTTP-запрос), то транзакция в первой базе остается открытой всё то время, пока выполняется внешний вызов. Давайте посмотрим на цепочку задержек:

  1. Установление сетевого соединения с удаленным сервером.
  2. Авторизация пользователя во второй базе и инициализация сеанса.
  3. Создание, заполнение и проведение документа во второй базе (что запускает вторую транзакцию на другом сервере СУБД).
  4. Формирование и отправка ответа обратно в первую базу.

В лучшем случае этот процесс занимает 2–3 секунды. В худшем — при нестабильной сети или высокой загрузке серверов — процесс может затянуться на 30–60 секунд или завершиться по таймауту. Всё это время таблицы первой базы заблокированы. Другие пользователи, пытающиеся провести свои заказы или накладные, выстраиваются в очередь блокировок. Спустя короткое время они начинают массово получать критическую ошибку: «Превышено время ожидания установки блокировки». Работа компании останавливается.

Кроме того, если во второй базе произойдет сбой (например, не хватило остатка товара), первая база должна отменить свою транзакцию. Но если сетевой пакет с подтверждением отмены потеряется, мы получим рассинхронизацию данных: в УТ заказ не проведен, а в УПП документ успешно создался и зарезервировал остатки. Разгребать такие последствия программистам приходится вручную.

Почему стоит раз и навсегда отказаться от COM-соединений?

Исторически использование COM-объектов (V83.COMConnector) было самым простым способом связать две базы. Однако этот подход имеет критические недостатки:

Рассмотрим современные архитектурные паттерны, которые позволяют решить задачу оперативного взаимодействия баз надежно и быстро.

Решение 1. Паттерн «Сага» (Saga Pattern) на основе статусов документов

Для того чтобы уйти от синхронного ожидания проведения во второй базе, мы можем применить паттерн разделения процесса на шаги с использованием статусов. Давайте разберем этот алгоритм по шагам:

  1. Менеджер в УТ 11 проводит документ ЗаказКлиента. В этот момент документ не делает движений по ключевым складским регистрам, а записывается в промежуточном статусе «Ожидает подтверждения». Транзакция СУБД завершается мгновенно (за доли секунды).
  2. При записи документа система автоматически регистрирует необходимость отправки этого заказа в УПП. Для этого мы создаем запись в специальном регистре сведений, выполняющем роль исходящей очереди задач (паттерн Transactional Outbox).
  3. С высокой частотой (например, раз в 5–10 секунд) в фоне работает регламентное задание. Оно считывает очередь, асинхронно обращается к УПП через быстрый HTTP-сервис и передает данные заказа.
  4. УПП принимает запрос, пытается провести документ у себя и возвращает результат в фоновое задание УТ.
  5. Фоновое задание в УТ, получив ответ от УПП, обновляет статус исходного документа:
    • Если в УПП проведение успешно — статус заказа в УТ меняется на «Подтвержден», и документ делает реальные движения по остаткам в УТ.
    • Если в УПП произошла ошибка (например, нет товара на складе) — статус заказа меняется на «Отклонен», а менеджер получает мгновенное оповещение через систему взаимодействия 1С или задачу.

Давайте посмотрим, как может выглядеть реализация регистрации документа в очереди обмена при его записи. Разместим этот код в модуле объекта документа ЗаказКлиента:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если документ проводится менеджером, временно устанавливаем статус ожидания
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        ЭтотОбъект.СтатусЗаказа = Перечисления.СтатусыЗаказов.ОжидаетПодтверждения;
    КонецЕсли;
    
КонецПроцедуры

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

Решение 2. Использование легковесных HTTP-сервисов (REST API)

Многие разработчики ошибочно полагают, что в старых конфигурациях на обычных формах (таких как УПП 1.3) невозможно опубликовать HTTP-сервисы. Это не так. Возможность создания HTTP-сервисов — это свойство самой платформы 1С 8.3, и она никак не зависит от того, какой интерфейс используется в конфигурации (управляемый или обычный).

Давайте спроектируем HTTP-сервис на стороне УПП 1.3, который будет принимать заказы из УТ 11, пытаться их проводить и возвращать результат в формате JSON. Это работает значительно быстрее, чем тяжелые SOAP-веб-сервисы или COM-соединения.

Создадим в конфигурации УПП новый HTTP-сервис с именем OrderIntegration, шаблоном URL /orders и методом POST, который привязан к функции СоздатьИПровестиЗаказ. Рассмотрим пример реализации этой функции в модуле HTTP-сервиса:


Функция СоздатьИПровестиЗаказ(Запрос)
    
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    
    // Читаем JSON с данными заказа из тела HTTP-запроса
    СтрокаДанных = Запрос.ПолучитьТелоКакСтроку("UTF-8");
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаДанных);
    ДанныеЗаказа = ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();
    
    // Пытаемся создать и провести документ в УПП
    НачатьТранзакцию();
    Попытка
        НовыйЗаказ = Документы.ЗаказПокупателя.СоздатьДокумент();
        НовыйЗаказ.Дата = ТекущаяДата();
        НовыйЗаказ.Заполнить(Неопределено); // Заполнение базовых реквизитов по умолчанию
        
        // Заполняем реквизиты данными из УТ
        НовыйЗаказ.Контрагент = Справочники.Контрагенты.НайтиПоКоду(ДанныеЗаказа.КодКонтрагента);
        НовыйЗаказ.ДоговорКонтрагента = НовыйЗаказ.Контрагент.ОсновнойДоговорКонтрагента;
        
        Для Каждого СтрокаТовара Из ДанныеЗаказа.Товары Цикл
            НоваяСтрока = НовыйЗаказ.Товары.Добавить();
            НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду(СтрокаТовара.КодНоменклатуры);
            НоваяСтрока.Количество = СтрокаТовара.Количество;
            НоваяСтрока.Цена = СтрокаТовара.Цена;
            НоваяСтрока.Сумма = СтрокаТовара.Количество * СтрокаТовара.Цена;
        КонецЦикла;
        
        // Записываем и проводим документ
        НовыйЗаказ.Записать(РежимЗаписиДокумента.Проведение);
        
        ЗафиксироватьТранзакцию();
        
        // Возвращаем успешный ответ со ссылкой на созданный документ
        Результат = Новый Структура;
        Результат.Вставить("Успешно", Истина);
        Результат.Вставить("НомерУПП", НовыйЗаказ.Номер);
        Результат.Вставить("ОписаниеОшибки", "");
        
    Исключение
        ОтменитьТранзакцию();
        
        // Возвращаем ошибку проведения
        Результат = Новый Структура;
        Результат.Вставить("Успешно", Ложь);
        Результат.Вставить("НомерУПП", "");
        Результат.Вставить("ОписаниеОшибки", КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
    // Записываем ответ в JSON
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, Результат);
    Ответ.УстановитьТелоИзСтроки(ЗаписьJSON.Закрыть(), "UTF-8");
    
    Возврат Ответ;
    
КонецФункции

Теперь на стороне УТ 11 фоновое регламентное задание может легко отправлять данные по HTTP-протоколу, используя объект HTTPСоединение. Такой подход работает молниеносно, не создает лишней нагрузки и легко масштабируется на любое количество пользователей.

Решение 3. Использование встроенного механизма OData

Если вам не хочется писать собственный HTTP-сервис для чтения или создания документов во второй базе, мы можем использовать стандартный программный интерфейс 1С — OData (автоматический REST-сервис платформы).

Для активации этого механизма достаточно запустить одну строчку кода в УПП, которая разрешит доступ к необходимым метаданным (например, к справочникам номенклатуры, контрагентов и документам заказов):


// Разрешаем удаленный доступ к документу ЗаказПокупателя по OData
МассивМетаданных = Новый Массив;
МассивМетаданных.Добавить(Метаданные.Документы.ЗаказПокупателя);
СистемаУправленияИнтерфейсомOData.УстановитьСоставИспользования(МассивМетаданных);

После этого внешняя база УТ сможет создавать документы в УПП простым HTTP-запросом к опубликованной базе по стандартному адресу вида: http://server/upp/odata/standard.odata/Document_ЗаказПокупателя. Платформа 1С самостоятельно преобразует входящие JSON-структуры в объекты базы данных УПП, выполнит все необходимые проверки и запишет документ.

Решение 4. Использование брокеров сообщений (RabbitMQ / Apache Kafka)

Для крупных корпоративных систем оптимальным решением является интеграция через специализированных посредников — брокеров сообщений. Рассмотрим эту схему подробнее:

Для реализации такой схемы в 1С, начиная с версии платформы 8.3.14, встроены специальные «Сервисы интеграции», позволяющие работать с внешними брокерами сообщений напрямую на уровне платформы без использования сторонних внешних компонент.

Подведем итоги

Пытаться связать две базы 1С синхронно в момент проведения документов — это опасный путь, ведущий к нестабильности СУБД и постоянным блокировкам пользователей. Использование COM-соединений внутри транзакций является устаревшим и вредным подходом.

Для построения отказоустойчивой и быстрой архитектуры всегда используйте асинхронные методы интеграции. Реализуйте очереди задач через регистры сведений и регламентные задания, разделяйте процессы проведения документов с помощью статусов, используйте современные легковесные HTTP-сервисы и интерфейс OData. Это гарантирует бесперебойную работу ваших информационных систем при любых нагрузках.

← На главную