У меня есть два связанных вопроса, касающихся соединений с концентратором SignalR, но прежде чем я получу их, я просто расскажу о том, что я делаю.
контекст
У меня есть приложение, которое отправляет уведомления с сервера клиенту интерфейса (Javascript) с помощью SignalR. Тем не менее, есть и клиент back-end (.NET), который создает прокси-сервер для концентратора. Клиент back-end обрабатывает уведомления и отправляет их в концентратор, а концентратор отправляет эти уведомления клиенту переднего конца.
Чтобы быть более конкретным, у меня есть класс обработки уведомлений, позвольте ему назвать NotificationProcessor.cs
. Каждый раз, когда создается новое уведомление, экземпляр NotificationProcessor
создается. Когда экземпляр NotificationProcessor
создается, устанавливается прокси-соединение с концентратором. У меня есть класс, HubProxyService.cs
, который создает HubConnection
объект и IHubProxy
объект от этого. Его фрагмент выглядит следующим образом:
this.HubConnection = new HubConnection(serverUrl);
this.HubProxy = HubConnection.CreateHubProxy(hubName);
Task t = Task.Run(() => this.HubConnection.Start(new LongPollingTransport()));
t.WaitAndUnwrap();
Затем NotificationProcessor
использует объект IHubProxy
для вызова методов в концентраторе.
Я обнаружил, что создание объекта HubConnection
каждый раз, когда NotificationProcessor
HubConnection
а не HubConnection
когда это происходит, вызывает утечку памяти.
Вопросы
(1) Чтобы избежать утечки памяти, мне нужно как-то избавиться от HubConnection
. Я читал, что могу сделать
Task.Run(() => this.HubConnection.Stop())
Проблема в том, что я не знаю, в какой момент я могу это назвать. Поскольку вызов метода хаба с прокси-сервером является асинхронным, могу ли я просто вызвать его сразу после вызова метода хаба? Или это вызовет проблемы в случае задержки отправки уведомления от концентратора переднему клиенту?
Я полагаю, что другой вариант заключается в том, чтобы обернуть инициализацию HubConnection в оператор using, например
using (HubConnection connection = new HubConnection(serverUrl))
{
}
Я слышал, что это может быть проблематично, потому что удаление HubConnection
может занять некоторое время.
Есть ли тот, который лучше другого? Последнее кажется более идиоматичным, в то время как первое является более явным и может работать лучше.
(2) HubConnection
идея создать HubConnection
для каждого созданного экземпляра NotificationProcessor
? Есть ли способ сохранить эту связь (т.е. Сделать ее статической или что-то подобное)? У меня есть шаткое понимание жизни объектов и побочных эффектов, особенно потому, что это приложение развертывается в облаке, и я не знаю, что это значит, что один экземпляр HubConnection
будет использоваться более одного раза. Разделяется ли он между потоками? Между узлами (я использую объединительную плату Redis)? Между пользователями? Имеет смысл держать соединение открытым, если дорого его поддерживать, когда оно нужно отправлять, но я просто не понимаю, как он работает, когда он развертывается в облаке на нескольких узлах. Мне просто кажется, что каждый раз нужно продолжать новую связь.
Этот вопрос был опубликован некоторое время назад, но, не заметив ответа, я подумал, что буду звонить.
Учитывая то, что вы описали, я лично рекомендовал, чтобы статический экземпляр HubConnection был повторно использован для каждого процессора с новым HubProxy для каждого процессора. Просто убедитесь, что IHubProxy можно правильно утилизировать, когда процессор расположен.
Каждое соединение будет рассматриваться как отдельный клиент для концентратора SignalR, поэтому, если вам нужны отдельные уведомления или клиенты внутри одного и того же процесса, вам понадобятся отдельные подключения, но в вашем случае кажется, что все эти уведомления происходят от одного и того же клиента,
Обязательно ознакомьтесь с безопасностью потока HubConnection.
Безопасность резьбы
Любые публичные статические (Shared in Visual Basic) члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют безопасность потоков.