Реализация Real-Time уведомлений через WebSocket на сайте
Представьте: пользователь оформляет заказ, но не получает уведомление об изменении статуса, пока не обновит страницу. Или модератор не видит новый комментарий до перезагрузки. Это не просто неудобство — это потеря конверсии и доверия. Мы — команда инженеров с пятилетним опытом — разрабатываем системы мгновенных уведомлений на WebSocket, которые доставляют события за миллисекунды, без лишних запросов к серверу. За 80+ проектов мы выработали надёжную архитектуру, выдерживающую пиковые нагрузки.
Почему WebSocket, а не polling?
При polling клиент каждые N секунд опрашивает сервер. При 10 000 пользователей, запрашивающих статус раз в 5 секунд, сервер получает 120 000 запросов в минуту — это огромная нагрузка и задержка до 5 секунд. WebSocket устанавливает постоянное соединение: данные поступают сразу, а трафик снижается в десятки раз. Мы используем WebSocket не только для чатов, но и для оповещений о статусах заказов, уведомлений от маркетплейсов, систем тикетов и любых задач, где нужна реактивность.
Какие проблемы решаем
Избыточный polling и нагрузка на сервер
Переход на WebSocket сокращает количество HTTP-запросов с сотен тысяч до нескольких сотен в час. На одном из проектов после замены polling на WebSocket нагрузка на backend упала на 80%, а затраты на инфраструктуру снизились в 2 раза — это экономия порядка 200 000 ₽ в месяц.
Доставка уведомлений офлайн-пользователям
Если пользователь закрыл вкладку, но хочет получать уведомления — мы сохраняем их в БД и отправляем при следующем подключении. В нашем решении это реализовано через Redis Pub/Sub с персистентностью. Дополнительно отправляем push-уведомление через FCM/APNS. Офлайн-доставка работает с задержкой не более 100 мс после подключения.
Масштабирование для тысяч соединений
Одно приложение может держать десятки тысяч WebSocket-соединений. Мы используем масштабирование через Redis или Kafka, чтобы соединения работали на нескольких инстансах. Нагрузочное тестирование подтверждает стабильность до 50 000 одновременных подключений.
Как обеспечивается доставка офлайн-пользователям?
В типичной архитектуре (см. код ниже) мы храним отображение userId → set<socketId>. Когда пользователь подключается, мы проверяем наличие неотправленных уведомлений в БД и доставляем их. Если пользователь офлайн — уведомление сохраняется со статусом pending.
// notification-ws.service.ts
class NotificationWebSocketService {
private userSockets = new Map<string, Set<string>>();
async onConnect(socket: Socket, userId: string) {
if (!this.userSockets.has(userId)) {
this.userSockets.set(userId, new Set());
}
this.userSockets.get(userId)!.add(socket.id);
socket.join(`user:${userId}`);
const pending = await this.notificationRepo.findUndelivered(userId);
if (pending.length > 0) {
socket.emit('notifications:batch', pending);
await this.notificationRepo.markDelivered(pending.map(n => n.id));
}
}
async sendToUser(userId: string, notification: Notification): Promise<void> {
const isOnline = this.userSockets.has(userId) &&
this.userSockets.get(userId)!.size > 0;
if (isOnline) {
io.to(`user:${userId}`).emit('notification:new', notification);
await this.notificationRepo.markDelivered([notification.id]);
} else {
await this.notificationRepo.save({ ...notification, status: 'pending' });
await this.pushService.send(userId, notification);
}
}
}
Почему React-хук useNotifications упрощает интеграцию?
На фронтенде мы подготовили React-хук, который подписывается на события socket.io. Он автоматически обрабатывает добавление новых уведомлений, подсчёт непрочитанных и отметку прочитанных. Всё, что нужно разработчику — вызвать useNotifications() и рендерить список.
// hooks/useNotifications.ts
function useNotifications() {
const [notifications, setNotifications] = useState<Notification[]>([]);
const [unreadCount, setUnreadCount] = useState(0);
const socket = useSocket();
useEffect(() => {
if (!socket) return;
socket.on('notification:new', (notification: Notification) => {
setNotifications(prev => [notification, ...prev]);
setUnreadCount(prev => prev + 1);
showToast(notification);
});
socket.on('notifications:batch', (batch: Notification[]) => {
setNotifications(prev => [...batch, ...prev]);
setUnreadCount(prev => prev + batch.filter(n => !n.readAt).length);
});
return () => {
socket.off('notification:new');
socket.off('notifications:batch');
};
}, [socket]);
const markAsRead = async (id: string) => {
await fetch(`/api/notifications/${id}/read`, { method: 'POST' });
setNotifications(prev =>
prev.map(n => n.id === id ? { ...n, readAt: new Date() } : n)
);
setUnreadCount(prev => Math.max(0, prev - 1));
};
const markAllAsRead = async () => {
await fetch('/api/notifications/read-all', { method: 'POST' });
setNotifications(prev => prev.map(n => ({ ...n, readAt: n.readAt || new Date() })));
setUnreadCount(0);
};
return { notifications, unreadCount, markAsRead, markAllAsRead };
}
Типы уведомлений и их визуализация
Мы определили типовые события для типичного приложения:
| Тип | Описание | Иконка |
|---|---|---|
| order:status_changed | Статус заказа изменился | 📦 |
| message:received | Новое сообщение в чате | 💬 |
| mention:comment | Упоминание в комментарии | @ |
| task:assigned | Назначена новая задача | ✅ |
| payment:processed | Платёж проведён | 💳 |
| system:alert | Системное предупреждение | ⚠️ |
Для каждого типа можно настроить длительность отображения Toast и действие по клику.
Сравнение polling и WebSocket
| Параметр | Polling | WebSocket |
|---|---|---|
| Задержка | 1–5 сек | < 100 мс |
| Нагрузка на сервер | Высокая | Низкая |
| Трафик | ~120 000 запросов/мин | ~1 000 сообщений/мин |
| Масштабирование | Сложно при большом числе клиентов | Легко с Redis/Kafka |
Что входит в работу
- Архитектурная документация: описание схемы взаимодействия, выбор стека (Socket.IO, Redis, PostgreSQL).
- Реализация backend-сервиса: WebSocket handler, интеграция с системой авторизации, обработка отключений.
- Frontend-модуль: React-хук, компонент колокольчика, Toast-уведомления.
- Интеграция с push-уведомлениями (FCM/APNS) — по желанию.
- Нагрузочное тестирование: проверка до 50 000 одновременных соединений.
- Инструкция по развёртыванию и обучение команды.
Мы гарантируем стабильную работу системы при пиковых нагрузках — опыт 5+ лет в разработке real-time решений и 80+ выполненных проектов говорят сами за себя. Свяжитесь с нами, чтобы обсудить ваш проект — мы поможем выбрать оптимальную архитектуру и реализуем под ключ. Получите консультацию прямо сейчас.
Процесс работы
- Аналитика — изучаем текущую архитектуру, определяем сценарии уведомлений, нагрузку.
- Проектирование — выбираем протокол (WebSocket, SSE), брокер сообщений (Redis, Kafka), схему хранения.
- Реализация — пишем backend + frontend, покрываем тестами.
- Интеграция — прикручиваем к существующему проекту (Laravel, Nest.js, Django и др.).
- Деплой и мониторинг — настраиваем CI/CD, логирование, алерты.
Сроки ориентировочно
Базовая реализация (WebSocket + React + хранение офлайн) — 7–10 дней. С интеграцией push-уведомлений и нагрузочным тестированием — 2–3 недели. Стоимость рассчитывается индивидуально — пишите, мы оценим ваш проект.







