Skip to content

DefaultHubLifetimeManager performs full enumeration of ConcurrentDictionary when calling SendUsersAsync (SendToAllConnections) #60092

Open
@Dimoner

Description

@Dimoner

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Currently, when SendUsersAsync is called in DefaultHubLifetimeManager, it performs a full iteration over the ConcurrentDictionary, checking all connections instead of retrieving the data in O(1) time complexity.

This can lead to performance issues as the iteration scales poorly with the number of connections. Moreover, this behavior is not intuitive, since other hub lifetime managers, such as RedisHubLifetimeManager, create separate channels for each user instead of storing all users under a single key and performing a full scan.

Describe the solution you'd like

I propose adding a separate dictionary to store connections by userId, similar to how groups and connections are already managed:
private readonly HubConnectionStore _connections = new HubConnectionStore(); private readonly HubGroupList _groups = new HubGroupList();
This would allow direct access to user connections in O(1) time, significantly improving performance, especially in high-load scenarios.

Additional context

The current approach affects performance when scaling large SignalR applications.
RedisHubLifetimeManager already follows a per-user channel approach, making it more efficient.
Introducing a userId-based dictionary would align the behavior of DefaultHubLifetimeManager with RedisHubLifetimeManager, making the API more consistent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-signalrIncludes: SignalR clients and servers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions