При активной работе с внешними API или веб-сервисами разработчики часто сталкиваются с ситуацией, когда после выполнения запросов в операционной системе или отладчике продолжают «висеть» открытые соединения — для диагностики таких проблем поможет инструмент мониторинга и анализа HTTP-запросов для 1С. На первый взгляд кажется, что простое обнуление переменной объекта должно закрывать канал связи, но в реальности механизмы платформы 1С и протокола HTTP работают несколько сложнее. В этой статье мы подробно разберем, как управлять жизненным циклом HTTPСоединение, почему соединения не закрываются мгновенно и какие инструменты у нас есть для управления этим процессом.
Для начала проанализируем, почему команда Соединение = Неопределено; не всегда приводит к немедленному разрыву сетевого сокета. Платформа 1С:Предприятие оптимизирована для высокой производительности, поэтому она использует так называемый пул соединений (Connection Pooling). Это означает, что после завершения обмена данными физическое TCP-соединение не разрывается сразу, а помещается в кэш. Если в ближайшее время (обычно в течение 60 секунд) программа снова обратится к тому же серверу, платформа использует уже открытый канал, экономя время на «рукопожатии» (handshake) и установке защищенного TLS-соединения.
Рассмотрим ситуацию с точки зрения операционной системы. Когда мы создаем объект HTTPСоединение, системные библиотеки (WinHTTP в Windows или libcurl в Linux) открывают порт. После уничтожения объекта в коде 1С, сокет может оставаться в состоянии TIME_WAIT или ESTABLISHED еще некоторое время. Выясним причину: это поведение заложено на уровне реализации стека TCP/IP для предотвращения ошибок при передаче задержавшихся пакетов данных.
Если наша задача — гарантированно сообщить серверу, что мы не планируем использовать это соединение повторно, мы должны использовать стандартные средства протокола HTTP/1.1. По умолчанию в 1С используется режим Keep-Alive, который поддерживает соединение активным. Разберем по шагам, как принудительно инициировать закрытие соединения со стороны клиента.
Для этого нам необходимо добавить специальный заголовок в объект HTTPЗапрос. Посмотрим на пример кода:
Сервер = "api.mysite.com";
Соединение = Новый HTTPСоединение(Сервер);
Запрос = Новый HTTPЗапрос("/v1/data");
// Явно указываем серверу, что соединение нужно закрыть после ответа
Запрос.Заголовки.Вставить("Connection", "close");
Ответ = Соединение.ВызватьHTTPМетод("GET", Запрос);
При получении такого заголовка удаленный сервер после отправки данных сам инициирует процедуру закрытия сокета. Это самый правильный способ с точки зрения сетевых стандартов, если вы делаете разовый запрос к ресурсу и не хотите плодить «спящие» соединения.
Часто возникает путаница между сетевым соединением (портом) и логическим сеансом в информационной базе 1С — решать задачу контроля ресурсов удобнее через обработка управления сеансами и соединениями 1С. Если вы обращаетесь к другой базе 1С через HTTP-сервисы, то даже после закрытия сетевого сокета на сервере может остаться висеть сеанс пользователя. Проанализируем решение этой проблемы.
Для завершения сеанса в информационной базе 1С необходимо использовать заголовок IBSession с директивой finish — для этого пригодится обработка завершения сеансов и освобождения ресурсов. Это особенно актуально при отладке, когда каждый новый запрос создает новую сессию, занимающую лицензию и память. Рассмотрим пример реализации:
Запрос = Новый HTTPЗапрос("/hs/my_service/get_data");
// Указываем платформе 1С на стороне сервера завершить сеанс после обработки
Запрос.Заголовки.Вставить("IBSession", "finish");
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Важный момент: данный заголовок работает только при обращении к веб-сервисам или HTTP-сервисам, опубликованным на платформе 1С. При работе со сторонними ресурсами (например, API банков или соцсетей) этот заголовок будет проигнорирован.
Посмотрим на ситуацию, когда соединений становится слишком много в процессе отладки — здесь поможет отладчик кода и инспектор переменных для 1С:Предприятие. Платформа удерживает соединение, пока объект HTTPСоединение доступен в памяти. Проанализируем два способа минимизации этого влияния:
HTTPСоединение без явной необходимости.Пример настройки таймаута:
// Установим таймаут в 10 секунд вместо стандартных 60
Таймаут = 10;
Соединение = Новый HTTPСоединение(ИмяСервера, , , , , Таймаут);
Выясним причину, по которой даже идеальный код на стороне 1С может не помогать. Иногда проблема кроется в настройках веб-сервера (IIS или Apache), на котором опубликован сервис. В настройках веб-сервера есть параметры KeepAliveTimeout (для Apache) или Connection Timeout (для IIS). Если эти значения слишком велики (например, несколько минут), то сервер будет принудительно держать соединение открытым, ожидая новых данных от клиента.
Если вы являетесь администратором системы, проверьте следующие настройки:
KeepAlive (должна быть On) и KeepAliveTimeout (рекомендуется 5-15 секунд).Мы проанализировали основные способы завершения HTTP-соединений — для этих задач есть готовый инструментарий для управления заданиями и отладки. В большинстве случаев штатное поведение платформы 1С с использованием пула соединений является оптимальным, так как оно экономит ресурсы на повторную авторизацию. Однако при необходимости принудительного разрыва следует комбинировать установку заголовка Connection: close, использование заголовка IBSession: finish для сервисов 1С и правильное управление временем жизни локальных переменных.
Помните, что полное мгновенное закрытие всех сокетов в состоянии TIME_WAIT на уровне операционной системы практически невозможно средствами встроенного языка 1С, так как это часть низкоуровневой работы сетевого стека, призванная обеспечить надежность передачи данных.