Проверяет умение проектировать ограничение на количество одновременных активных чатов пользователя с учётом гонок между вкладками и устройствами.
Задача кажется простой, пока пользователь работает в одной вкладке. Но как только открыто несколько вкладок или устройств, локальные проверки вроде if (activeChats.length < 1) перестают работать: каждая вкладка видит только своё состояние и может одновременно создать чат. Значит, источник истины должен быть общим и атомарным.
active_chats с уникальным индексом по user_id (если разрешён ровно один активный чат).active_chat:{userId} с TTL и атомарной операцией SET NX.Ключевой приём — не «проверить, потом создать», а сделать проверку и создание одной атомарной операцией. В SQL это транзакция с уникальным индексом, в Redis — SET NX или Lua-скрипт.
-- PostgreSQL: уникальный индекс гарантирует один активный чат
CREATE UNIQUE INDEX uniq_active_chat
ON chats (user_id)
WHERE status = 'active';
-- Создание в транзакции
BEGIN;
INSERT INTO chats (user_id, status) VALUES ($1, 'active');
COMMIT;
-- При гонке второй INSERT упадёт с unique_violation
// Redis: атомарный захват слота
const ok = await redis.set(
`active_chat:${userId}`,
chatId,
{ NX: true, EX: 3600 }
);
if (!ok) throw new Error('У пользователя уже есть активный чат');
Даже с серверным лимитом вкладки должны узнавать об изменениях, чтобы UI не расходился. Для этого подойдут BroadcastChannel, storage-события или WebSocket-подписка на события пользователя.
const bc = new BroadcastChannel('chats');
bc.onmessage = (e) => {
if (e.data.type === 'chat-created') refreshChats();
};
// после успешного создания
bc.postMessage({ type: 'chat-created' });
Клиент может отправить два запроса подряд (двойной клик, ретрай). Чтобы не создавать дубликаты, используй идемпотентный ключ запроса и возвращай уже созданный чат, если он есть. На сервере лови ошибку уникальности и отвечай 409 Conflict с текущим активным чатом.
Итог: ограничение активных чатов должно жить на сервере в атомарном хранилище (БД или Redis), а вкладки синхронизировать через BroadcastChannel или WebSocket. Такой подход устойчив к гонкам, ретраям и работе с нескольких устройств.
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию