Разберем классическую архитектурную задачу при интеграции 1С со сторонними системами. База 1С опубликована на веб-сервере, и на нее регулярно приходят входящие HTTP-запросы. Нам необходимо максимально быстро принять данные, отдать внешней системе успешный ответ, а уже после окончания работы функции обработки запроса — выполнить "тяжелые" действия (например, создать, заполнить и провести 4 и более документов). Проанализируем, как реализовать такую логику правильно, чтобы не перегрузить систему и гарантировать сохранность данных.
Первое, что часто приходит на ум — это вызвать фоновое задание в самом конце обработчика HTTP-ответа. Посмотрим, как выглядит этот подход. Мы получаем данные, формируем массив параметров и передаем их в метод ФоновыеЗадания.Выполнить, после чего возвращаем ответ.
// Пример вызова фонового задания напрямую из HTTP-сервиса
ПараметрыЗадачи = Новый Массив;
ПараметрыЗадачи.Добавить(СтруктураДанныхИзЗапроса);
// Запускаем асинхронный процесс
ФоновыеЗадания.Выполнить("МодульИнтеграции.ОбработатьДанныеАсинхронно", ПараметрыЗадачи);
// Мгновенно возвращаем ответ клиенту
Ответ = Новый HTTPСервисОтвет(200);
Возврат Ответ;
Недостатки подхода: Как справедливо отмечают разработчики, если входящих запросов будет много, такой подход может быстро "положить на лопатки" сервер 1С из-за неконтролируемого пложения фоновых заданий. Каждое фоновое задание забирает ресурсы процессора, а массовое параллельное создание и проведение документов приведет к жестким транзакционным блокировкам на уровне SQL. Этот метод подходит только для редких запросов с минимальной нагрузкой.
Выясним причину проблем первого способа — это отсутствие контроля над потоком выполнения. Чтобы избежать пиковых нагрузок, сформируем очередь действий в отдельном регистре сведений и будем циклично обрабатывать её регламентными заданиями. Разберем по шагам, как это работает:
ОчередьВходящихЗапросов).200 OK. Время ответа составит миллисекунды.
// Пример быстрой фиксации запроса в очередь
МенеджерЗаписи = РегистрыСведений.ОчередьВходящихЗапросов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИдентификаторЗапроса = Строка(Новый УникальныйИдентификатор);
МенеджерЗаписи.ТелоЗапроса = СтрокаJSON;
МенеджерЗаписи.Статус = Перечисления.СтатусыОчереди.Новый;
МенеджерЗаписи.Записать();
Ответ = Новый HTTPСервисОтвет(200);
Возврат Ответ;
Этот подход гарантирует, что сервер не упадет от SQL транзакций, так как проведение документов будет выполняться в один или несколько контролируемых потоков.
Вместо того чтобы изобретать велосипед с собственными регистрами, рассмотрим использование готовой подсистемы ОчередьЗаданий, которая встроена в Библиотеку стандартных подсистем (БСП). Эта подсистема берет на себя всю рутину:
Проанализируем ситуацию: клиент отправил нам запрос, мы положили задачу в очередь, но из-за моргания сети клиент не получил наш ответ 200 OK. По таймауту клиент отправит запрос повторно. Если мы просто запишем его в очередь еще раз, система создаст документы дважды.
Чтобы избежать этого, применим паттерн Idempotency-Key. В заголовках HTTP-запроса внешняя система должна передавать уникальный идентификатор операции. При получении запроса 1С ищет этот ключ в своей очереди. Если ключ уже существует, 1С просто возвращает успешный ответ (или статус ранее запущенной задачи), игнорируя повторное добавление в очередь записи.
Рассмотрим дополнительные архитектурные паттерны для высоконагруженных систем:
1. Внешние брокеры сообщений. Если входящих запросов тысячи в секунду, запись даже в регистр сведений 1С может стать узким местом. В этом случае HTTP-сервис 1С при получении запроса пробрасывает сообщение во внешний брокер (например, RabbitMQ или Apache Kafka) и моментально завершает работу. Отдельный рабочий процесс 1С спокойно вычитывает сообщения из брокера батчами (пакетами) и обрабатывает их без перегрузки SQL.
2. Разделение кластера 1С. Чтобы фоновые процессы (проведение множества документов) не тормозили обработку новых входящих HTTP-соединений, настроим кластер 1С. С помощью механизма "Требования назначения функциональности" жестко маршрутизируем все фоновые и регламентные задания на отдельный рабочий сервер. Таким образом, тяжелые расчеты будут забирать ресурсы процессора только на сервере фоновых заданий.
3. Паттерн отложенного получения данных. В классическом REST API правильным ответом на запрос, который ставится в очередь, является не 200 OK, а 202 Accepted ("Принято в обработку"). В теле ответа 1С должна отдавать уникальный ID сформированной задачи. Сторонняя система сможет периодически отправлять легкий GET-запрос по этому ID к 1С, чтобы проверить статус: выполнилась ли задача, создались ли документы, или процесс все еще находится в обработке.
Применяя описанные подходы с очередями и контролем потоков, вы создадите надежную, масштабируемую систему, способную обрабатывать огромное количество HTTP-запросов без вреда для производительности основного контура 1С.