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