Задать вопрос
DenisSoloviev
@DenisSoloviev
Frontend-разработчик

Как правильно организовать real-time обновление в огромном проекте?

Проблема:
В приложении Next.js используется общий сокет для трансляции спортивных событий. При обрыве интернета (или переключении устройства) логика восстановления комнат срабатывает нестабильно. Часто теряются поля в объектах, или TanStack Query не обновляет кеш, потому что ключи формируются неправильно

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

Вопрос:
Стоит ли делать отдельный провайдер, который обернет все приложение, будет следить за pathname, так как по нему формируется подписка на некоторые события, также будет подписываться на события, восстанавливать подключения и следить где какой кеш нужно обновить в зависимости от типа события?
Есть ли более масштабируемый паттерн для управления одним большим сокетом на проекте?

Если нужны еще детали, могу уточнить, хочу понять как строить полноценный реалтайм сервис, а не просто игрушку из пары хуков в компонентах
  • Вопрос задан
  • 108 просмотров
Подписаться 1 Сложный Комментировать
Помогут разобраться в теме Все курсы
  • Нетология
    1C-программист: расширенный курс
    18 месяцев
    Далее
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
  • ProductStar × РБК
    Профессия: Инженер по информационной безопасности
    9 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 2
opium
@opium
Просто люблю качественно работать
Провайдер нужен, но лучше не делать из него «бога». Разбей на слои: transport (только connect/reconnect/auth), subscription registry (хранит активные комнаты, при reconnect сам делает join), и event handlers где setQueryData если пришёл полный объект, invalidateQueries если partial. pathname — только сигнал «какие комнаты сейчас нужны», не основа архитектуры. И один queryKeys factory вместо строк в каждом хуке — это сразу уберёт половину несовпадений ключей.

p.s. после reconnect обязателен resync (snapshot по HTTP или sync_required событие) — socket.io recovery при долгом обрыве не гарантирован.
Ответ написан
VoidVolker
@VoidVolker
Dark side eye. А у нас печеньки! А у вас?
Делал так:
  • Основная идея — stateless паттерн
  • Ноды "WS фронтенд" — только связь с клиентами, тупо проброс сообщений между сокетом и очередью, плюс пинг клиентов и обновление TTL у своих сессий
  • Ноды "WS бэкенд" — бизнес-логика, коннект к БД, через связь "клиент <-> нода" в редиске отправляет сообщения в нужную фронт-ноду
  • Сессии в редиске — глобальный список связей "клиент <-> нода", ноды онлайн, ID их очередей, а вот у каждой фронт-ноды свой список сессий подключённых к ней клиентов и всякими дополнительными данными типа сессионных токенов, плюс у сессий ограничения по TTL — по истечении времени она автоматом уничтожается
  • Очереди — та же редиска, у каждой ноды своя пара очередей вх/исх, формат — сырые бинарные данные, дабы не лишний раз не заниматься конвертацией туда-сюда
  • Фичи WS протокола: аутентификация, авторизация, сообщения, подтверждение доставки сообщений, редирект на другой сервер — фича для балансировки и безопасного отключения клиентов от ноды и для её отключения, в случае потери связи клиенты реконнектятся по дефолтному урлу

Да, возможно не самое оптимальное решение, но задача была сделать "вчера и масштабируемо" (ну, как обычно) — поэтому максимально просто и тупо. Зато можно пачками плодить ноды, из узких мест — тут, конечно, в первую очередь БД, во вторую — дополнительная нагрузка и задержки на пересылку сообщений фронт-редис-бэк. В остальном вполне юзабельное решение. Чисто технически редиску можно вообще выкинуть из цепочки пересылки и оставить её только для сессий и других внутренних данных.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы