Почему HTTP-сервис в 1С создает дубли документов и как это исправить?

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

При реализации интеграций через HTTP-сервисы в 1С:Предприятие 8.3 разработчики часто сталкиваются с крайне неприятным эффектом: один логический запрос от внешней системы приводит к созданию двух или более одинаковых документов. Ситуация осложняется тем, что при анализе логов выполнение кода может выглядеть «разорванным» или задвоенным внутри одной процедуры. Разберем подробно, почему это происходит и как выстроить архитектуру сервиса, исключающую подобные сбои.

Выясняем причины: почему управление «прыгает», а документы множатся?

Прежде чем приступать к коду, проанализируем ситуацию на уровне транспортного протокола и платформы. Существует несколько неочевидных факторов, провоцирующих такое поведение:

  1. Прозрачные повторы (Transparent Retries): Если ваш веб-сервер (IIS или Apache) или промежуточный узел (балансировщик, прокси) не получает ответа от 1С в течение заданного тайм-аута, он может разорвать соединение и автоматически отправить запрос повторно. Клиент об этом может даже не знать, но в 1С придет второй запрос.
  2. Особенности пула соединений: В 1С HTTP-сервисы работают в рамках пула. Если при обработке первого запроса произошел сетевой сбой, сеанс может не завершиться мгновенно. Платформа (особенно в версиях 8.3.17–8.3.20) в некоторых случаях может пытаться «довыполнить» код или некорректно восстановить состояние сеанса при повторном обращении.
  3. Неблокирующая запись лога: Часто кажется, что код «прыгнул» в середину процедуры, потому что текстовый лог записывается без жестких блокировок. Когда два потока пишут в один файл одновременно, строки перемешиваются, создавая иллюзию хаоса.

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

Решение 1: Обеспечение идемпотентности через уникальный ключ

Идемпотентность — это свойство метода при повторном вызове выдавать тот же результат, что и при первом, не изменяя состояние системы повторно. Метод POST, который обычно используется для создания документов, не является идемпотентным по умолчанию. Чтобы это исправить, мы должны внедрить механизм «ключа идемпотентности».

Разберем алгоритм реализации:

  1. Внешняя система при каждом запросе обязана генерировать уникальный идентификатор (GUID или ID транзакции) и передавать его в теле запроса или заголовке.
  2. В 1С мы должны сохранять этот ID в созданном документе (например, в дополнительном реквизите) или в специальном регистре сведений.
  3. При поступлении запроса мы первым делом проверяем наличие ID в базе.

Посмотрим на пример кода в модуле HTTP-сервиса:


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

    // Если проверка пройдена, создаем документ
    Возврат СоздатьНовыйОбъект(СтруктураДанных);
    
КонецФункции

Важный нюанс: Чтобы избежать ситуации, когда два запроса пришли почти одновременно и проверка в обоих случаях показала, что документа еще нет, рекомендуется добавить проверку также в модуль объекта документа в процедуру ПередЗаписью. Это обеспечит транзакционную целостность на уровне базы данных.

Решение 2: Использование фоновых заданий (асинхронная модель)

Если процесс создания документа занимает значительное время (проверки, проведение, сложные расчеты), риск разрыва соединения веб-сервером по тайм-ауту возрастает. В этом случае правильнее перевести сервис на асинхронную работу.

Проанализируем шаги этой схемы:

  1. HTTP-сервис получает данные и быстро записывает их в «очередь» (например, в Регистр Сведений) или сразу запускает фоновое задание.
  2. Сервис тут же возвращает клиенту ответ 202 Accepted.
  3. Создание документа происходит в отдельном сеансе фонового задания, который не зависит от стабильности HTTP-соединения.

Пример реализации запуска фонового задания:


ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(СтруктураДанных);

ФоновыеЗадания.Выполнить("ВашОбщийМодуль.СоздатьДокументИзСервиса", ПараметрыЗадания, ИдентификаторТранзакции, "Интеграция с внешней системой");

Ответ = Новый HTTPСервисОтвет(202);
Ответ.УстановитьТелоИзСтроки("Данные приняты в обработку");
Возврат Ответ;

Использование ИдентификаторТранзакции в качестве ключа уникальности фонового задания (третий параметр функции Выполнить) предотвратит запуск двух одинаковых заданий одновременно, если запросы все же задвоились на входе.

Решение 3: Глубокая диагностика через системные идентификаторы

Чтобы окончательно выяснить причину «безумия» в логах, необходимо добавить в логирование контекст исполнения. Если вы видите создание двух документов, нужно понять: это один и тот же сеанс 1С или два разных?

Добавьте в ваш файл логирования вывод следующих параметров:

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

Дополнительные рекомендации по стабильности

Проанализируем еще несколько технических моментов, которые могут влиять на результат:

  1. Режим записи: Вместо двойного вызова (сначала Записать(), потом Записать(РежимЗаписиДокумента.Проведение)), всегда используйте одну операцию записи в нужном режиме. Это сокращает количество транзакций и снижает риск блокировок.
  2. Очистка кэша: В редких случаях странное поведение HTTP-сервисов лечится очисткой серверного кэша 1С и перезагрузкой веб-сервера (IIS/Apache). Это актуально после динамического обновления конфигурации или изменений в расширениях.
  3. Транзакционный лог: Вместо текстового файла на диске попробуйте записывать события в Журнал регистрации 1С или в отдельный Регистр Сведений. Это гарантирует, что записи лога будут подчиняться правилам транзакций и вы точно увидите, какая ветка кода в итоге была зафиксирована в базе данных.

Подводя итог: в 90% случаев проблема «странных сбоев» HTTP-сервиса кроется в отсутствии контроля идемпотентности на стороне 1С при повторных запросах от нестабильных сетей. Внедрение уникальных ключей транзакций и переход на фоновые задания сделают вашу интеграцию максимально надежной.

← На главную