Search code examples
c#servicestackservicestack.redis

Infinite Redis Client loop and StackOverflow


I have a strange thing, impossible to find a solution until now.

We use 4 Redis servers (Master and slaves).

Impossible to get my object on Redis, even if this one exists. Please HELP !

I'm a registered Redis user.

Please see this video where I explain the problem:

https://youtu.be/HAem8aqS4yw

Here's my code:

private static RedisSentinel _redisSentinel;
private static IRedisClientsManager _redisManager;

private static IRedisClientsManager GetRedisSentinel()
{
    try
    {
        if (_redisSentinel == null || _redisManager == null)
        {
            List<string> listSentinels = new List<string>();
            listSentinels.Add(ConfigurationManager.AppSettings["RedisDB1"]);
            listSentinels.Add(ConfigurationManager.AppSettings["RedisDB2"]);
            listSentinels.Add(ConfigurationManager.AppSettings["RedisDB3"]);
            listSentinels.Add(ConfigurationManager.AppSettings["RedisDB4"]);

            _redisSentinel = new RedisSentinel(listSentinels, ConfigurationManager.AppSettings["RedisMaster"])
            {
                OnWorkerError = ex =>
                {
                    _logRedis.Info( "Worker error: {0}" + ex.Message, ex);
                },
                OnFailover = redisClient =>
                {
                    _logRedis.Info("Fail over: {0}" + redisClient);
                    redisClient.Dispose();
                },
                OnSentinelMessageReceived = (s1,s2) =>
                {
                    _logRedis.Info(string.Format("Sentinel message: {0} - {1}", s1, s2));
                }
            };

            _redisSentinel = new RedisSentinel(listSentinels, ConfigurationManager.AppSettings["RedisMaster"]);
            _redisSentinel.RedisManagerFactory = (master, slaves) => new RedisManagerPool(master);
            _redisManager = _redisSentinel.Start();


            _log.Trace("Open REDIS Connection: OK.");
        }


    }
    catch (Exception ex)
    {
        _log.Trace(ex, "Error Redis Connection: " + ex.Message);
    }

    return _redisManager;
}

public static object GetRedisCache<T>(string key)
{
    object myObject = null;

    //naming convention [PLATFORM]:[PROJECT]:[FUNCTION]:[PARAMETERS…]
    string redisKey = string.Format("WEB:{0}:{1}:{2}", _redisProject, typeof (T), key);

    try
    {
        //Open Redis
        IRedisClientsManager redisManager = GetRedisSentinel(); // <- jump -----------<
        if (redisManager != null)
        {

            using (RedisClient redis = (RedisClient) redisManager.GetClient()) 
            {

                //here: the problem occurs, No crash, No Exception
                //just it roll back again to line GetRedisSentinel(), see my video
                myObject = redis.Get<T>(redisKey);  //--> jump directly to ------------^
            }

        }


    }
    catch (Exception ex)
    {
        _log.Trace(ex, "Error Get In Redis: " + ex.Message);
    }

    return myObject;
}

Solution

  • Please read the docs on ServiceStack.Redis there should only be 1 singleton instance of either a RedisManager or RedisSentinel which you should create only once on StartUp.

    So I recommend changing it to only create 1 instance of RedisSentinel and IRedisClientsManager which you can maintain in a static variable.

    It's not clear why you're recursively calling yourself and the code you've provided wont reproduce this issue but I expect the callstack will reveal what the issue is, which may have something to do with the class definition of the generic T Type you're trying to deserialize.

    Note: in order for this to occur something needs to be calling GetRedisCache<T>() again, this has nothing to do with the Redis Client which has no knowledge about your GetRedisCache<T>() method, the only thing it's trying to do is deserialize an instance of T so I would look at any code gets run on deserialization as something else is eventually directly or indirectly calling yourself again. I would inspect your callstack to see what the code-path that leads to this is.