Как отправить HTTP-запрос из 1С без ожидания ответа сервера (Fire and Forget)

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

В практике интеграции систем часто возникает ситуация, когда одной базе 1С необходимо инициировать действие в другой базе через HTTP-запрос, но при этом само действие (например, проведение тяжелого документа) занимает значительное время (10–30 секунд). Ожидание ответа в основном потоке приводит к "зависанию" интерфейса пользователя или задержке выполнения серверного кода. Рассмотрим подробнее, как реализовать механизм отправки запроса по принципу "выстрелил и забыл" (fire and forget), чтобы программа продолжала работу сразу после отправки данных.

Способ 1. Использование механизма фоновых заданий

Проанализируем наиболее "нативный" для платформы 1С метод — делегирование отправки запроса фоновому заданию (см. пример работы с фоновыми заданиями). Этот метод позволяет основному потоку завершиться мгновенно, в то время как платформа создаст отдельный сеанс на сервере для выполнения HTTP-соединения.

Разберем по шагам реализацию этого метода. Сначала создадим процедуру в общем модуле (модуль должен быть серверным с установленной галочкой "Вызов сервера"):


Процедура ОтправитьЗапросФоново(ПараметрыЗапроса) Экспорт
    // ПараметрыЗапроса - Структура с URL, заголовками и телом
    НТТПСоединение = Новый HTTPСоединение(ПараметрыЗапроса.Сервер);
    НТТПЗапрос = Новый HTTPЗапрос(ПараметрыЗапроса.Ресурс);
    // Здесь логика заполнения запроса...
    Попытка
        Ответ = НТТПСоединение.ВызватьHTTPМетод("GET", НТТПЗапрос);
    Исключение
        ЗаписьЖурналаРегистрации("ОшибкаHTTP", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

Затем вызовем эту процедуру из кода документа или обработки с помощью метода ФоновыеЗадания.Выполнить:


Параметры = Новый Структура;
Параметры.Вставить("Сервер", "api.myserver.ru");
Параметры.Вставить("Ресурс", "/v1/repost?id=123");

МассивПараметров = Новый Массив;
МассивПараметров.Добавить(Параметры);

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

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

Способ 2. Очередь сообщений через Регистр Сведений (Отложенная отправка)

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

Создадим РегистрСведений "ОчередьHTTPЗапросов" со следующими полями:

  1. Объект (ЛюбаяСсылка) — ссылка на документ, который нужно перепровести.
  2. Статус (Перечисление) — "Новый", "В процессе", "Ошибка".
  3. КоличествоПопыток (Число).

Теперь вместо отправки запроса мы просто записываем данные в этот регистр. Выполнение запроса поручим регламентному заданию, которое будет запускаться раз в минуту и обрабатывать записи. Рассмотрим пример кода для регламентного задания:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 10 СсылкаНаДокумент ИЗ РегистрСведений.ОчередьHTTPЗапросов ГДЕ Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗапросов.Новый)";
Результат = Запрос.Выполнить().Выбрать();

Пока Результат.Следующий() Цикл
    // Логика отправки HTTP-запроса
    // Если успешно - удаляем запись или меняем статус
    // Если ошибка - увеличиваем счетчик попыток
КонецЦикла;

Этот подход гарантирует доставку и позволяет системе работать максимально быстро, так как запись в регистр происходит за миллисекунды (для масштабируемых систем рассмотрите DaJet MQ).

Способ 3. Асинхронные методы платформы (версии 8.3.18+)

Посмотрим на современные возможности платформы. В новых версиях появились методы с префиксом Начать..., такие как НачатьВызовHTTPМетода. Они используют механизм ОписанияОповещения.

Проанализируем ситуацию: хотя эти методы чаще используются в тонком клиенте для неблокирующего ожидания, они позволяют реализовать логику, при которой код продолжает выполнение. Однако для серверных вызовов (где обычно происходит проведение документов) фоновые задания остаются более предпочтительными.

Способ 4. Использование WinHTTP через COM-объект (для Windows)

Если нам нужно отправить запрос максимально "тихо" и быстро без создания полноценного фонового задания 1С, мы можем воспользоваться объектом WinHttp.WinHttpRequest.5.1. У этого объекта есть возможность асинхронной отправки через параметр метода Open.


WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
// Пятый параметр (Async) устанавливаем в Истина (True)
WinHttp.Open("GET", "http://server.com/api/repost", Истина);
WinHttp.Send();

В данном случае метод Send() не блокирует выполнение кода 1С. Система отправляет запрос в стек сетевой службы Windows и сразу возвращает управление программе.

Способ 5. Архитектурное решение на стороне базы-приемника (HTTP 202 Accepted)

Рассмотрим ситуацию с точки зрения протокола HTTP. Правильным подходом при обработке "тяжелых" запросов является использование статуса 202 Accepted.

  1. База-источник делает обычный HTTP-запрос.
  2. База-приемник в HTTP-сервисе не начинает сразу проводить документ.
  3. Приемник создает ФоновоеЗадание у себя внутри для обработки документа.
  4. Приемник мгновенно возвращает ответ со статусом 202.
  5. База-источник получает этот ответ мгновенно (сетевая задержка минимальна) и продолжает работу.

Пример кода на стороне базы-приемника (HTTP-сервис):


Функция ПерепровестиДокумент(Запрос)
    Параметры = Новый Массив;
    Параметры.Добавить(Запрос.ПараметрыURL.Получить("id"));
    
    // Запускаем тяжелую операцию в фоне на стороне приемника
    ФоновыеЗадания.Выполнить("ИнтеграцияПрием.ПровестиДокументФоново", Параметры);
    
    Ответ = Новый HTTPСервисОтвет(202); // Accepted
    Возврат Ответ;
КонецФункции

Способ 6. Запуск внешних утилит (curl или PowerShell)

Если необходимо полностью исключить влияние процесса отправки на стабильность сеанса 1С, можно использовать системную утилиту curl или PowerShell через метод ЗапуститьПриложение. У этого метода есть параметр ДождатьсяЗавершения, который нужно установить в Ложь.


// Пример для curl (должен быть установлен в ОС)
Команда = "curl -X GET ""http://myserver.ru/repost?id=777""";
ЗапуститьПриложение(Команда, , Ложь);

// Пример для PowerShell
КомандаPS = "powershell -Command ""Invoke-WebRequest -Uri 'http://myserver.ru/repost?id=777'""";
ЗапуститьПриложение(КомандаPS, , Ложь);

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

Выводы и рекомендации

Мы проанализировали различные подходы к реализации неблокирующих HTTP-запросов. Выбор метода зависит от ваших задач:

← На главную