Перейти к основному содержимому
Версия: 4.x

Рассылки

Рассылка (broadcast) — это сообщение, инициированное сервером, с именем действия и необязательными данными. Клиенты получают его в виде { "id": "@", "action": "…", "data": … }.

Публикуйте рассылку из обработчика через методы Broadcast*Async класса HandlerBase или из любого сервиса, внедрив IBroadcaster:

public sealed class OrderNotifier(IBroadcaster broadcaster) {
public Task OrderShippedAsync(Order order, CancellationToken ct) =>
broadcaster.BroadcastToGroupAsync(
$"account:{order.AccountId}",
"order:shipped",
new { order.Id, order.TrackingNumber },
ct);
}

Перегрузки без данных не отправляют поле data. Перегрузки с данными тоже опускают data, если значение равно null.

Получатели​

Получателей определяет вызываемый метод:

МетодПолучатели
BroadcastAsync(action, …)Все подключения
BroadcastToConnectionAsync(connectionId, action, …) (только IBroadcaster)Одно подключение
BroadcastToSessionAsync(sessionId, action, …)Все подключения одной сессии, например все вкладки пользователя
BroadcastToGroupAsync(group, action, …)Подключения, в сессии которых указана эта группа
BroadcastToSelfAsync(action, …) (только в обработчиках)Вызывающее подключение

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

Семантика доставки​

  • Выбор получателей использует один снимок индексов групп и сессий.
  • Сериализация выполняется один раз на рассылку; все получатели используют одни и те же байты.
  • Локальная доставка пишет получателям параллельно, ограниченное число за раз. Сокет, который не принимает запись в течение BroadcastSendTimeout (10 секунд), обрывается.
  • Порядок рассылок, опубликованных одновременно, не гарантируется. Если порядок важен, добавляйте в данные версию или порядковый номер.
  • Отмена: с in-memory backplane токен публикующей стороны передаётся и в локальную доставку. Его отмена во время доставки рассылки пропускает оставшихся получателей и отменяет выполняющиеся записи, что обрывает эти сокеты. Redis backplane проверяет токен только перед публикацией.
  • Завершение: с in-memory backplane метод рассылки завершается после локальной доставки; с Redis — когда Redis принимает сообщение.
  • Без повторной доставки: отключённый клиент пропускает рассылку. Считайте рассылки уведомлениями об изменениях и заставляйте клиентов перезагружать состояние после переподключения.

Подключения и группы​

Внедрите singleton ConnectionStorage, чтобы просматривать локальные подключения:

public sealed class PresenceService(ConnectionStorage connections) {
public int OnlineInAccount(Guid accountId) =>
connections.GetByGroup($"account:{accountId}").Count;
}
ЧленНазначение
GetAll()Все подключения на этом экземпляре
GetByConnection(id)Подключение с этим идентификатором или пустая коллекция
GetBySession(id)Подключения одной сессии
GetByGroup(name)Участники одной группы
Add(connection)Добавляет или заменяет подключение по идентификатору и заново считывает группы его сессии в индексы
Remove(connection)Удаляет именно это подключение; возвращает false, если его нет или оно было заменено

DarkWS сам добавляет и удаляет подключения. Запросы возвращают снимки.

Снимок групп делается при добавлении подключения и после каждого auth: или logout. Если ваша сессия предоставляет группы, которые меняются независимо, снова вызовите Add(connection), чтобы обновить индексы. Add не проверяет, открыто ли ещё подключение: повторное добавление уже удалённого подключения регистрирует его снова.

Эти запросы видят только текущий экземпляр. С Redis рассылки всё равно доходят до подключений на всех экземплярах.

Backplane​

Broadcaster передаёт каждое сообщение в IDarkWsBackplane, который доставляет его на каждый экземпляр сервера. Стандартный in-memory backplane обслуживает один экземпляр. Для нескольких экземпляров используйте Redis backplane. Код обработчиков не меняется при смене backplane.

Собственный backplane реализует PublishAsync(DarkWsBroadcast), SubscribeAsync(listener) и UnsubscribeAsync(). DarkWS подписывается при запуске хоста и отписывается при его остановке. Зарегистрируйте backplane как singleton IDarkWsBackplane через services.Replace(...) или через AddSingleton до вызова AddDarkWs().