В процессе разработки интеграций в 1С часто возникает ситуация, когда необходимо инициировать отправку данных во внешнюю систему, но при этом не блокировать выполнение основного кода или работу пользователя. По умолчанию стандартный объект 1С HTTPСоединение работает синхронно: программа отправляет запрос и «замирает», ожидая ответа от сервера. Если сервер долго обрабатывает данные, работа в 1С приостанавливается. Рассмотрим подробнее, как реализовать принцип «выстрелил и забыл» (fire and forget) в среде 1С.
Самый правильный и надежный способ сделать HTTP-запрос асинхронным в рамках платформы 1С — это запуск процедуры отправки в фоновом задании. Это позволяет основному потоку мгновенно продолжить выполнение, в то время как сервер 1С создаст отдельный сеанс для выполнения сетевой операции.
Разберем по шагам, как это реализовать. Сначала создадим процедуру в общем модуле (модуль должен иметь флаг «Сервер» и «Вызов сервера» или быть глобальным серверным модулем):
// Общий модуль: ИнтеграцияВызовСервера
Процедура ОтправитьЗапросФоновымЗаданием(ПараметрыЗапроса) Экспорт
Попытка
Соединение = Новый HTTPСоединение(ПараметрыЗапроса.АдресСервера);
Запрос = Новый HTTPЗапрос(ПараметрыЗапроса.Ресурс);
Запрос.УстановитьТелоИзСтроки(ПараметрыЗапроса.Данные);
// Здесь выполнение остановится до получения ответа,
// но это не заблокирует основной поток пользователя
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Исключение
// Логируем ошибку, так как пользователь ее не увидит
ЗаписьЖурналаРегистрации("HTTP_Асинхрон", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Теперь проанализируем, как вызвать этот код из основной обработки или документа, не дожидаясь завершения:
ПараметрыВызова = Новый Структура;
ПараметрыВызова.Вставить("АдресСервера", "api.myserver.com");
ПараметрыВызова.Вставить("Ресурс", "/v1/data");
ПараметрыВызова.Вставить("Данные", "{'status': 'done'}");
// Запускаем фоновое задание и сразу идем дальше
ФоновыеЗадания.Выполнить("ИнтеграцияВызовСервера.ОтправитьЗапросФоновымЗаданием", ПараметрыВызова);
Важный нюанс: при использовании фоновых заданий следует помнить, что каждое такое задание расходует лицензию на сеанс (в некоторых версиях платформы). Если запросов сотни в минуту, лучше использовать очередь сообщений.
Если нам нужно максимально абстрагироваться от ресурсов 1С и не занимать сеансы фоновыми заданиями, мы можем делегировать отправку запроса операционной системе. Для этого отлично подходит утилита cURL, которая предустановлена во многих дистрибутивах Linux и последних версиях Windows 10/11.
Проанализируем ситуацию: мы вызываем внешнее приложение, которое работает независимо от процесса 1cv8.exe. Для этого используем метод ЗапуститьПриложение. Рассмотрим пример для Windows:
Команда = "cmd /c start /b curl -X POST https://api.site.com/endpoint -d ""data=test""";
ЗапуститьПриложение(Команда, , Ложь); // Третий параметр Ложь означает "не ждать завершения"
В этом примере параметры означают следующее:
cmd /c start /b — запускает консольную команду в фоновом режиме, не открывая нового окна.curl — сама утилита для HTTP-запроса.Ложь (в методе 1С) — основной поток 1С не будет ждать, пока cURL закончит свою работу.Для тонкой настройки асинхронности можно использовать COM-объект WinHttp.WinHttpRequest.5.1. Он поддерживает асинхронный режим работы на уровне самой библиотеки Windows.
Выясним, как настроить этот объект. В методе Open пятый параметр Async отвечает за асинхронность:
HttpЗапрос = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
// Параметры: Метод, URL, Асинхронно (True)
HttpЗапрос.Open("POST", "http://example.com/api", Истина);
HttpЗапрос.SetRequestHeader("Content-Type", "application/json");
// Запрос улетает, и управление сразу возвращается в 1С
HttpЗапрос.Send("{'key': 'value'}");
Предупреждение: При использовании этого метода объект HttpЗапрос может быть уничтожен сборщиком мусора 1С сразу после выхода из процедуры, что может привести к обрыву соединения до того, как данные уйдут. Рекомендуется объявлять переменную объекта на уровне модуля или формы, чтобы «продлить ей жизнь».
Существует специфический подход, когда мы намеренно ограничиваем время ожидания ответа до минимума. Рассмотрим ситуацию, когда нам важно только то, чтобы сервер «увидел» начало передачи данных.
// Устанавливаем таймаут в 1-2 секунды
Соединение = Новый HTTPСоединение("myserver.com", , , , , 1);
Запрос = Новый HTTPЗапрос("/fast-api");
Попытка
Соединение.ОтправитьДляОбработки(Запрос);
Исключение
// Если произошел таймаут — скорее всего, запрос уже ушел на сервер,
// но ответ мы не дождались. Просто игнорируем ошибку.
КонецПопытки;
Почему это плохой способ: Вы никогда не будете уверены, дошел ли запрос. Пакет может потеряться в сети до того, как попадет на сервер, и вы не получите никакого уведомления об этом.
При реализации асинхронных запросов важно учитывать следующие моменты:
Журнал Регистрации или специальный регистр сведений.Подведем итог: если вам нужно быстрое и «штатное» решение внутри 1С — используйте ФоновыеЗадания. Если вы хотите сэкономить ресурсы сервера 1С и работаете под Windows — используйте cURL через ЗапуститьПриложение.