Пример #1
0
        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();
        }
Пример #3
0
        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();
                }
            }
        }
Пример #5
0
        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);
                }
            });
        }