PooledRedisClientManager not releasing connections

2019-03-21 12:37发布

问题:

I am storing lists of json data in redis and accessing it using the ServiceStack c# client. I am essentially managing my own foreign keys, where I store a zrange of ids and I use an interface internal to my application to pull the id's from the zrange and then fetch the underlying json objects from Redis and package them as a list to return to other parts of my application.

I am using the PooledRedisClientManager as I anticipate Redis to be hosted on a different server from the server executing the code.

I am doing all my development work locally on Windows 8, using the MSOpenTech Redis server. Currently my biggest challenge is that client connections are not being closed.

My Redis persister is being injected with an instance of IRedisClientManager (IoC is CastleWindsor). This code executes in the context of an azure worker role.

This is how I am fetching items from a zrange:

public class MyRedisPersister<T> : IResourcePersister<T>
{ 
    IRedisClientManager _mgr;
    public MyRedisPersister(IRedisClientManager mgr)
    {
        _mgr = mgr;
    }

    public IResourceList<T> Get<T>(string key, int offset, int count) where T
    {
        using (var redis = _clientManager.GetClient())
        {
            var itemKeys = redis.GetRangeFromSortedSet(key, offset, offset + count - 1).ToList();
            var totalItems = redis.GetSortedSetCount(key);

            if (itemKeys.Count == 0)
            {
                return new ResourceList<T>
                    {
                        Items = new List<T>(),
                        Offset = 0,
                        PageSize = 0,
                        TotalItems = 0,
                        TotalPages = 0
                    };
            }
            else
            {
                return new ResourceList<T>
                    {
                        Items = itemKeys.Select(k => redis.Get<T>(k)).ToList(),
                        Offset = offset,
                        PageSize = count,
                        TotalItems = totalItems,
                        TotalPages = (int) Math.Ceiling((float) totalItems/count)
                    };
            }
        }
    }
}

This is the code I use to register the IRedisClientManager

var mgr = new PooledRedisClientManager(100, 10, "localhost:6379");
container.Register(Component.For<IRedisClientsManager>().Instance(mgr).LifeStyle.Singleton);

Any help would be greatly appreciated.

回答1:

Currently my biggest challenge is that client connections are not being closed.

You are using the 'PooledRedisClientManager' so my understanding is that the client connections should not be closed, just put into the pool for reuse. It looks like your pool size is 100 connections.

You can try using var mgr = new BasicRedisClientManager("localhost:6379") which should dispose of the client.



回答2:

edit The below approach is not recommended - you should take a dependency on the IRedisClientsManager and wrap all redis client calls inside a using() block, otherwise you will be bitten by gremlins.

I've been having similar problems getting Windsor to play nicely with the PooledRedisClientsManager, in the end this seemed to work:

        container.Register(
            Component.For<IRedisClientsManager>()
                     .Instance(redisClients)
                     .LifestyleSingleton(),

            Component.For<IRedisClient>()
                     .UsingFactoryMethod(c => c.Resolve<IRedisClientsManager>().GetClient(),
                                        managedExternally: true));
    }

The managedExternally parameter tells Windsor to not try to apply decommissioning concerns to the IRedisClients and let the PooledRedisClientsManager handle recycling.