private async Task EnsureRedisServerConnection() { if (_redisServerConnection == null) { await _connectionLock.WaitAsync(); try { if (_redisServerConnection == null) { var writer = new LoggerTextWriter(_logger); _redisServerConnection = await _options.ConnectAsync(writer); _bus = _redisServerConnection.GetSubscriber(); _redisServerConnection.ConnectionRestored += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionRestored(_logger); }; _redisServerConnection.ConnectionFailed += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionFailed(_logger, e.Exception); }; if (_redisServerConnection.IsConnected) { RedisLog.Connected(_logger); } else { RedisLog.NotConnected(_logger); } await SubscribeToAll(); await SubscribeToGroupManagementChannel(); await SubscribeToAckChannel(); } } finally { _connectionLock.Release(); } } }
public RedisHubLifetimeManager(ILogger <RedisHubLifetimeManager <THub> > logger, IOptions <RedisOptions> options, IHubProtocolResolver hubProtocolResolver) { _logger = logger; _options = options.Value; _ackHandler = new AckHandler(); _channels = new RedisChannels(typeof(THub).FullName); _protocol = new RedisProtocol(hubProtocolResolver.AllProtocols); var writer = new LoggerTextWriter(logger); RedisLog.ConnectingToEndpoints(_logger, options.Value.Options.EndPoints, _serverName); _redisServerConnection = _options.Connect(writer); _redisServerConnection.ConnectionRestored += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionRestored(_logger); }; _redisServerConnection.ConnectionFailed += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionFailed(_logger, e.Exception); }; if (_redisServerConnection.IsConnected) { RedisLog.Connected(_logger); } else { RedisLog.NotConnected(_logger); } _bus = _redisServerConnection.GetSubscriber(); SubscribeToAll(); SubscribeToGroupManagementChannel(); SubscribeToAckChannel(); }
public RedisHubLifetimeManager(ILogger <RedisHubLifetimeManager <THub> > logger, IOptions <RedisOptions> options) { _logger = logger; _options = options.Value; _ackHandler = new AckHandler(); var writer = new LoggerTextWriter(logger); _logger.ConnectingToEndpoints(options.Value.Options.EndPoints); _redisServerConnection = _options.Connect(writer); _redisServerConnection.ConnectionRestored += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } _logger.ConnectionRestored(); }; _redisServerConnection.ConnectionFailed += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } _logger.ConnectionFailed(e.Exception); }; if (_redisServerConnection.IsConnected) { _logger.Connected(); } else { _logger.NotConnected(); } _bus = _redisServerConnection.GetSubscriber(); SubscribeToHub(); SubscribeToAllExcept(); SubscribeToInternalGroup(); SubscribeToInternalServerName(); }
private async Task EnsureRedisServerConnection() { if (_defaultServer == null || _shardingServers == null) { await _connectionLock.WaitAsync(); try { if (_defaultServer == null || _shardingServers == null) { var writer = new LoggerTextWriter(_logger); var tasks = _options.Configurations.Select(async configuration => { var serverName = _options.ServerNameGenerator.GenerateServerName(); RedisLog.ConnectingToEndpoints(_logger, configuration.Options.EndPoints, serverName); var redisConnection = await _options.ConnectAsync(configuration.Options, writer); var server = new ShardingRedisServer(serverName, configuration.IsDedicatedForAllChannel, redisConnection, _logger); SubscribeToGroupManagementChannel(server); SubscribeToAckChannel(server); return(server); }).ToArray(); var redisServers = await Task.WhenAll(tasks); _defaultServer = redisServers.FirstOrDefault(server => server.IsDedicatedForAllChannel) ?? redisServers.First(); SubscribeToAll(_defaultServer); var shardingServers = redisServers.Where(server => !server.IsDedicatedForAllChannel); _shardingServers = shardingServers.ToArray(); } } finally { _connectionLock.Release(); } } }
private static ConnectionMultiplexer ConnectToRedis(RedisOptions options, ILogger logger) { var loggerTextWriter = new LoggerTextWriter(logger); if (options.Factory != null) { return(options.Factory(loggerTextWriter)); } if (options.Options.EndPoints.Any()) { return(ConnectionMultiplexer.Connect(options.Options, loggerTextWriter)); } var configurationOptions = new ConfigurationOptions(); configurationOptions.EndPoints.Add(IPAddress.Loopback, 0); configurationOptions.SetDefaultPorts(); return(ConnectionMultiplexer.Connect(configurationOptions, loggerTextWriter)); }
public RedisHubLifetimeManager(ILogger <RedisHubLifetimeManager <THub> > logger, IOptions <RedisOptions> options) { _logger = logger; _options = options.Value; _ackHandler = new AckHandler(); var writer = new LoggerTextWriter(logger); _logger.LogInformation("Connecting to redis endpoints: {endpoints}", string.Join(", ", options.Value.Options.EndPoints.Select(e => EndPointCollection.ToString(e)))); _redisServerConnection = _options.Connect(writer); if (_redisServerConnection.IsConnected) { _logger.LogInformation("Connected to redis"); } else { // TODO: We could support reconnecting, like old SignalR does. throw new InvalidOperationException("Connection to redis failed."); } _bus = _redisServerConnection.GetSubscriber(); var previousBroadcastTask = Task.CompletedTask; var channelName = _channelNamePrefix; _logger.LogInformation("Subscribing to channel: {channel}", channelName); _bus.Subscribe(channelName, async(c, data) => { await previousBroadcastTask; _logger.LogTrace("Received message from redis channel {channel}", channelName); var message = DeserializeMessage <HubMessage>(data); // TODO: This isn't going to work when we allow JsonSerializer customization or add Protobuf var tasks = new List <Task>(_connections.Count); foreach (var connection in _connections) { tasks.Add(WriteAsync(connection, message)); } previousBroadcastTask = Task.WhenAll(tasks); }); var allExceptTask = Task.CompletedTask; channelName = _channelNamePrefix + ".AllExcept"; _logger.LogInformation("Subscribing to channel: {channel}", channelName); _bus.Subscribe(channelName, async(c, data) => { await allExceptTask; _logger.LogTrace("Received message from redis channel {channel}", channelName); var message = DeserializeMessage <RedisExcludeClientsMessage>(data); var excludedIds = message.ExcludedIds; // TODO: This isn't going to work when we allow JsonSerializer customization or add Protobuf var tasks = new List <Task>(_connections.Count); foreach (var connection in _connections) { if (!excludedIds.Contains(connection.ConnectionId)) { tasks.Add(WriteAsync(connection, message)); } } allExceptTask = Task.WhenAll(tasks); }); channelName = _channelNamePrefix + ".internal.group"; _bus.Subscribe(channelName, async(c, data) => { var groupMessage = DeserializeMessage <GroupMessage>(data); if (groupMessage.Action == GroupAction.Remove) { if (!await RemoveGroupAsyncCore(groupMessage.ConnectionId, groupMessage.Group)) { // user not on this server return; } } if (groupMessage.Action == GroupAction.Add) { if (!await AddGroupAsyncCore(groupMessage.ConnectionId, groupMessage.Group)) { // user not on this server return; } } // Sending ack to server that sent the original add/remove await PublishAsync($"{_channelNamePrefix}.internal.{groupMessage.Server}", new GroupMessage { Action = GroupAction.Ack, ConnectionId = groupMessage.ConnectionId, Group = groupMessage.Group, Id = groupMessage.Id }); }); // Create server specific channel in order to send an ack to a single server var serverChannel = $"{_channelNamePrefix}.internal.{_serverName}"; _bus.Subscribe(serverChannel, (c, data) => { var groupMessage = DeserializeMessage <GroupMessage>(data); if (groupMessage.Action == GroupAction.Ack) { _ackHandler.TriggerAck(groupMessage.Id); } }); }