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

Конфигурация и ограничения

Настраивайте DarkWsOptions через AddDarkWs, services.Configure<DarkWsOptions>, привязку конфигурации или PostConfigure; они применяются в стандартном порядке Options:

builder.Services.AddDarkWs(options => {
options.MaxMessageSizeBytes = 256 * 1024;
options.MaxConcurrentRequestsPerConnection = 8;
options.AllowedOrigins.Add("https://app.example.com");
});

builder.Services.Configure<DarkWsOptions>(builder.Configuration.GetSection("DarkWs"));

Опции валидируются при первом разрешении и при запуске хоста; недопустимые значения приводят к OptionsValidationException. Подключения и singleton-сервисы запоминают используемые опции, поэтому изменение опций во время работы не перенастраивает существующие подключения.

Опции​

ОпцияПо умолчаниюЗначение
MaxMessageSizeBytes1 MiBМаксимальный размер полного входящего сообщения с учётом всех фрагментов
JsonOptionsJsonSerializerDefaults.WebСериализация конвертов и payload
AllowNullPayloadsfalseПередавать null в non-nullable ссылочные параметры
MaxConcurrentRequestsPerConnection16Число одновременно выполняемых действий на одном подключении
RequestQueueTimeout5 sОжидание места в очереди до BusyError
RunActionsOnThreadPoolfalseЗапускать действия в пуле потоков
KeepAliveInterval30 sИнтервал keep-alive транспорта
KeepAliveTimeout30 sДедлайн PONG на уровне транспорта (.NET 9 и новее)
ReceiveIdleTimeout2 minДедлайн ожидающего чтения (.NET 8)
SendTimeout30 sОжидание блокировки отправки плюс запись в сокет
BroadcastSendTimeout10 sДедлайн записи рассылки для каждого получателя
ShutdownTimeout10 sОбработчики, хуки закрытия и close handshake при остановке
AllowedOriginsпусто (любые)Браузерные origin, которым разрешено открывать эндпоинт
AuthenticationQueryParametertokenПараметр запроса, передаваемый аутентификатору при upgrade
AcceptAnonymousOnUpgradeAuthenticationExceptionfalseПринимать анонимно, если аутентификатор при upgrade выбрасывает исключение
KeepSessionOnFailedAuthenticationfalseСохранять сессию после неудачного auth:
InvalidActionErrordarkws:error:invalid-actionКод для неизвестных действий
InvalidRequestErrordarkws:error:invalid-requestКод для некорректных запросов и payload
AuthorizationRequiredErrordarkws:error:authorization-requiredКод для анонимных вызовов защищённых действий
RequestFailedErrordarkws:error:request-failedКод для непредвиденных сбоев
BusyErrordarkws:error:busyКод для запросов, отклонённых из-за заполненной очереди

Все таймауты должны быть положительными и не превышать 4294967294 миллисекунды.

Размер сообщения​

MaxMessageSizeBytes проверяется до разбора JSON и охватывает все фрагменты сообщения, включая команды аутентификации. Сообщение, размер которого ровно равен лимиту, принимается. Более крупное сообщение закрывает подключение со статусом 1009 (Message Too Big), и частично полученное сообщение не обрабатывается. Повышайте лимит, только если приложение действительно отправляет большие сообщения: вместе с ним растёт память на подключение.

Конкурентность запросов и backpressure​

У каждого подключения своя очередь:

  • Одновременно выполняется до MaxConcurrentRequestsPerConnection запросов (от 1 до int.MaxValue - 4).
  • Ещё столько же обычных запросов ожидают в порядке FIFO.
  • Четыре дополнительных места зарезервированы для auth: и logout, которые сохраняют свой порядок относительно запросов.
  • Отдельная входная очередь вмещает до MaxConcurrentRequestsPerConnection + 4 сообщений, пока один обработчик допуска ожидает места в очереди выполнения. Порядок поступления запросов и команд сохраняется.
  • Транспортные PONG продолжают читаться под нагрузкой. На текстовый ping отвечает отдельный обработчик с одним ожидающим слотом; повторные ping объединяются, пока запись занята.

Обычный запрос, ожидающий места для выполнения дольше RequestQueueTimeout, получает darkws:error:busy. Чтение сокета продолжается во время ожидания и отправки ответов. Переполнение входной очереди или допуск команды в заполненную очередь выполнения закрывает подключение со статусом 1008 (Policy Violation).

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

DarkWS ограничивает работу только внутри одного подключения. Общее число подключений и лимиты на пользователя или IP задавайте в хосте или reverse proxy.

Проверка активности​

DarkWS обнаруживает «мёртвые» пиры по-разному в зависимости от рантайма:

  • .NET 9 и 10: сервер отправляет транспортные PING каждые KeepAliveInterval и обрывает подключение, если PONG не пришёл в течение KeepAliveTimeout.
  • .NET 8: каждое ожидающее чтение из сокета ограничено ReceiveIdleTimeout, который сбрасывается при получении каждого фрагмента. Простаивающие клиенты должны отправлять трафик приложения в пределах этого времени. Клиенты DarkWS по умолчанию отправляют текстовый ping каждые 30 секунд. Транспортные PONG не учитываются. Ожидание допуска в очередь выполнения не приостанавливает таймер чтения.

Оба клиента также обнаруживают «мёртвые» серверы с помощью собственного таймаута ping/pong.

Отправка и остановка​

  • SendTimeout охватывает ожидание блокировки отправки подключения и запись в сокет. По истечении сокет обрывается.
  • Рассылки используют более короткий BroadcastSendTimeout для каждого получателя, поэтому медленный клиент не может задержать остальных.
  • При остановке подключение сразу удаляется из хранилища. Закрытие со стороны клиента отменяет токены действий, аутентификации, её хуков и отправки ответов на команды. ShutdownTimeout — единый дедлайн для незавершённых действий и команд, хуков закрытия и close handshake; после него сокет обрывается.
  • Callbacks, игнорирующие отмену, сохраняют свой scope и отложенные ресурсы подключения до завершения. Остановка всё равно ограничена дедлайном; запоздавшие результаты аутентификации и ответы отбрасываются. Нужные значения HTTP-контекста следует скопировать заранее: запрос обновления соединения уже может завершиться.
  • Принятый сокет закрывается и освобождается также при ошибке первоначальной регистрации сессии, включая исключения из её Id или Groups.

JSON​

JsonOptions общий для всех обработчиков. По умолчанию свойства прикладных DTO используют camelCase, а чтение не учитывает регистр. Имена полей конверта id, action, data и error закреплены атрибутами JsonPropertyName и не меняются от политики именования. Клиенты должны соблюдать схему DTO внутри data. Конверт Redis использует независимые настройки сериализации.

Логирование​

  • Успешные действия и некорректные запросы клиентов логируются на уровне Debug.
  • Непредвиденные сбои обработчиков и ошибки аутентификации при upgrade логируются как предупреждения.
  • Сообщения исключений обработчиков попадают в лог, но никогда не отправляются клиентам.