/// <summary>
        /// Adds an existing <see cref="IConnectionMultiplexer"/> to the cache manager configuration which can be referenced by redis cache handle and/or backplane.
        /// </summary>
        /// <param name="part">The builder instance.</param>
        /// <param name="configurationKey">
        /// The configuration key which can be used to refernce this configuration by a redis cache handle or backplane.
        /// </param>
        /// <param name="redisClient">The connection multiplexer instance.</param>
        /// <param name="database">The redis database to use for caching.</param>
        /// <param name="enableKeyspaceNotifications">
        /// Enables keyspace notifications to react on eviction/expiration of items.
        /// Make sure that all servers are configured correctly and 'notify-keyspace-events' is at least set to 'Exe', otherwise CacheManager will not retrieve any events.
        /// See <see href="https://redis.io/topics/notifications#configuration"/> for configuration details.
        /// </param>
        /// <returns>The configuration builder.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// If <paramref name="configurationKey"/> or <paramref name="redisClient"/> are null.
        /// </exception>
        public static ConfigurationBuilderCachePart WithRedisConfiguration(this ConfigurationBuilderCachePart part, string configurationKey, IConnectionMultiplexer redisClient, int database = 0, bool enableKeyspaceNotifications = false)
        {
            Guard.NotNullOrWhiteSpace(configurationKey, nameof(configurationKey));

            Guard.NotNull(redisClient, nameof(redisClient));

            var connectionString = redisClient.Configuration;

            part.WithRedisConfiguration(configurationKey, connectionString, database, enableKeyspaceNotifications);

            RedisConnectionManager.AddConnection(connectionString, redisClient);

            return(part);
        }
Exemple #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RedisCacheHandle{TCacheValue}"/> class.
        /// </summary>
        /// <param name="managerConfiguration">The manager configuration.</param>
        /// <param name="configuration">The cache handle configuration.</param>
        /// <param name="loggerFactory">The logger factory.</param>
        /// <param name="serializer">The serializer.</param>
        public RedisCacheHandle(ICacheManagerConfiguration managerConfiguration, CacheHandleConfiguration configuration, ILoggerFactory loggerFactory, ICacheSerializer serializer)
            : base(managerConfiguration, configuration)
        {
            Guard.NotNull(loggerFactory, nameof(loggerFactory));
            Guard.NotNull(managerConfiguration, nameof(managerConfiguration));
            Guard.NotNull(configuration, nameof(configuration));
            Guard.EnsureNotNull(serializer, "A serializer is required for the redis cache handle");

            Logger = loggerFactory.CreateLogger(this);
            _managerConfiguration = managerConfiguration;
            _valueConverter       = new RedisValueConverter(serializer);
            _redisConfiguration   = RedisConfigurations.GetConfiguration(configuration.Key);
            _connection           = new RedisConnectionManager(_redisConfiguration, loggerFactory);
            _isLuaAllowed         = _connection.Features.Scripting;

            // disable preloading right away if twemproxy mode, as this is not supported.
            _canPreloadScripts = _redisConfiguration.TwemproxyEnabled ? false : true;

            if (_redisConfiguration.KeyspaceNotificationsEnabled)
            {
                // notify-keyspace-events needs to be set to "Exe" at least! Otherwise we will not receive any events.
                // this must be configured per server and should probably not be done automagically as this needs admin rights!
                // Let's try to check at least if those settings are configured (the check also works only if useAdmin is set to true though).
                try
                {
                    var configurations = _connection.GetConfiguration("notify-keyspace-events");
                    foreach (var cfg in configurations)
                    {
                        if (!cfg.Value.Contains("E"))
                        {
                            Logger.LogWarn("Server {0} is missing configuration value 'E' in notify-keyspace-events to enable keyevents.", cfg.Key);
                        }

                        if (!(cfg.Value.Contains("A") ||
                              (cfg.Value.Contains("x") && cfg.Value.Contains("e"))))
                        {
                            Logger.LogWarn("Server {0} is missing configuration value 'A' or 'x' and 'e' in notify-keyspace-events to enable keyevents for expired and evicted keys.", cfg.Key);
                        }
                    }
                }
                catch
                {
                    Logger.LogDebug("Could not read configuration from redis to validate notify-keyspace-events. Most likely useAdmin is not set to true.");
                }

                SubscribeKeyspaceNotifications();
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="RedisCacheBackplane"/> class.
        /// </summary>
        /// <param name="configuration">The cache manager configuration.</param>
        /// <param name="loggerFactory">The logger factory</param>
        public RedisCacheBackplane(ICacheManagerConfiguration configuration, ILoggerFactory loggerFactory)
            : base(configuration)
        {
            Guard.NotNull(configuration, nameof(configuration));
            Guard.NotNull(loggerFactory, nameof(loggerFactory));

            _logger      = loggerFactory.CreateLogger(this);
            _channelName = configuration.BackplaneChannelName ?? "CacheManagerBackplane";
            _identifier  = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString());

            var cfg = RedisConfigurations.GetConfiguration(ConfigurationKey);

            _connection = new RedisConnectionManager(
                cfg,
                loggerFactory);

            RetryHelper.Retry(() => Subscribe(), configuration.RetryTimeout, configuration.MaxRetries, _logger);
        }