Эфир 18.11 · Поток 318 ноября в 19:00 МСК — бесплатный практический эфир по ИИ-агентам · Живой Поток 3 стартует 23.11Эфир 18 ноября →Поток 3 (23.11)
РелизAPI / Продукт · В работуModal Blog→ оригинал

Modal закрепляет сессию за 1 контейнером и сохраняет контекст при переподключении

Голосовой агент может держать разговор в памяти, пока после обрыва связи клиент не попадёт в другой контейнер. Modal выпустила Sticky Sessions: запросы одной сессии возвращаются к одному процессу, а инфраструктура масштабируется по числу активных сессий. Это полезно для голосовых ботов, интерфейсов на Gradio и общих комнат; восстановление состояния после сбоя контейнера нужно продумывать отдельно.

AI-обработка оригинала Modal Blog; редакция Hamidun News
Modal закрепляет сессию за 1 контейнером и сохраняет контекст при переподключении
Источник: Modal Blog. Коллаж: Hamidun News.
Слушать статью
Паспорт материала и цифры
ПараметрДанные
ПервоисточникModal Blog ↗
Главный редактор
Ключевой факт #1Токен сессии направляет запросы в контейнер, который хранит её состояние.
Ключевой факт #2Новые сессии ждут свободного места или запуска дополнительного контейнера.
Ключевой факт #3Привязка действует в рамках жизни сессии и не заменяет сохранение данных.

Голосовой бот разговаривает с пользователем, соединение обрывается, пользователь подключается снова — и попадает к процессу, который ничего о нём не знает. Для серверной инфраструктуры это может быть нормальным распределением нагрузки. Для продукта это сломанный разговор. Modal представила Sticky Sessions: механизм, который направляет запросы одной сессии в один и тот же контейнер и масштабирует инфраструктуру по количеству активных сессий.

На практике разработчик получает возможность держать временное состояние рядом с работающим кодом: контекст голосового агента, состояние декодера распознавания речи или общую игровую комнату. При переподключении запрос возвращается туда, где это состояние уже находится, пока сессия продолжает жить.

Почему одного WebSocket недостаточно

Представим сервис тренировки собеседований с голосовым ИИ. В контейнере работают агент и обработка аудио, там же находится состояние текущего разговора. Пользователь переключается с Wi-Fi на мобильный интернет. Соединение приходится устанавливать заново, но продукт должен продолжить собеседование с того же места.

Как объясняет Modal, WebSocket в её Web Functions привязан к отдельному вызову функции. После разрыва возникает новый вызов, который может попасть в другой контейнер. Сам по себе WebSocket поэтому не решает задачу возвращения к прежнему процессу.

Обходной путь — ограничить приложение одним контейнером. Тогда запросам просто некуда уйти, однако вместе с проблемой маршрутизации исчезает возможность горизонтального масштабирования. У Modal Servers также есть маршрутизация по заголовку Modal-Affinity-Routing-Key, но она работает по возможности: контейнер могут остановить или заменить.

Sticky Sessions вводят более строгую привязку на время сессии. Это особенно полезно приложениям на Gradio и Streamlit, где пользовательское состояние связано с конкретным серверным процессом. Разработчику не приходится удерживать весь сервис в единственном экземпляре ради непрерывности отдельных пользовательских сценариев.

Как запрос находит нужный процесс

Для подключения механизма класс Modal Server помечают декоратором @modal.sessioned(), после чего создают сессию через SDK или HTTP API. В приведённом компанией примере вызов sessions.start(idle_timeout=600) возвращает объект с токеном. Клиент передаёт этот токен в заголовке Modal-Authorization при последующих запросах.

Токен подписан и содержит сведения, необходимые для маршрутизации. Прокси проверяет его и отправляет запрос контейнеру, которому принадлежит сессия. Благодаря этому прокси не нужно поддерживать отдельную согласованную таблицу соответствий между сессиями и контейнерами на всех своих экземплярах.

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

Меняется и единица масштабирования. Контейнер принимает заданное количество одновременных сессий. Когда свободных мест нет, новые сессии ждут завершения существующих или готовности дополнительного контейнера. Автомасштабирование учитывает активные сессии и очередь, поскольку уже начатый разговор нельзя произвольно перебросить на соседний процесс.

Что проверить перед внедрением

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

Есть и вопрос распределения нагрузки. Две сессии могут потреблять разное количество ресурсов: короткая текстовая беседа и непрерывный аудиопоток дают совершенно разную нагрузку. Поэтому количество сессий на контейнер придётся выбирать под реальный сценарий. Существующую тяжёлую сессию механизм не переносит автоматически ради выравнивания нагрузки.

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

Сюжет

Вопросы и ответы по материалу

Что известно по теме: почему одного WebSocket недостаточно?

Представим сервис тренировки собеседований с голосовым ИИ. В контейнере работают агент и обработка аудио, там же находится состояние текущего разговора. Пользователь переключается с Wi-Fi на мобильный интернет. Соединение приходится устанавливать заново, но продукт должен продолжить собеседование с того же места. Как объясняет Modal, WebSocket в её Web Functions привязан к отдельному вызову функции. После разрыва возникает новый вызов, который может попасть в другой контейнер.

Что известно по теме: как запрос находит нужный процесс?

Для подключения механизма класс Modal Server помечают декоратором @modal.sessioned(), после чего создают сессию через SDK или HTTP API. В приведённом компанией примере вызов sessions.start(idle_timeout=600) возвращает объект с токеном. Клиент передаёт этот токен в заголовке Modal-Authorization при последующих запросах. Токен подписан и содержит сведения, необходимые для маршрутизации. Прокси проверяет его и отправляет запрос контейнеру, которому принадлежит сессия.

Что известно по теме: что проверить перед внедрением?

Главное ограничение: закрепление маршрута не означает сохранность данных при сбое контейнера. В публикации описана непрерывность обращений в рамках сессии, но не обещано восстановление её памяти после аварии. Историю разговоров, результаты работы и другие важные данные по-прежнему нужно сохранять отдельно, если продукт должен переживать такие события. Есть и вопрос распределения нагрузки.

ЖХ
Жемал Хамидун — CPO Alpina Digital, продакт-менеджер AlpinaGPT. Делает AI-продукты с 2019 года. Hamidun News — pet project, который вырос в production-агрегатор с 6000+ читателей.
✦ Единое AI-пространство · Nomad

Протестируйте новые LLM и мультимодальные модели в одном окне

Платформа Nomad AI (nomadnet.ai) даёт прямой доступ к Claude Opus 5.5, GPT-6, Gemini 3.1, DeepSeek и автономным агентам без VPN, зарубежных карт и зоопарка подписок.

Открыть Nomad AI →Автономный Nomad Agent
Что вы думаете?
Загружаем комментарии…