Radu Cotofana
Radu Cotofana

Reputation: 117

ServiceStack PooledRedisClient Timeout exception

I am using ServiceStack.Redis pooled client in a servicestack API and after a couple of hours of traffic with about 3000rpm I receive a connection timeout exception from the pool manager. The implementation is as follows:

In AppStart:

 container.Register<IRedisClientsManager>(
                    p => new RedisManagerPool(Configuration.Config.Instance.RedisConfig.Server)
                    {
                        MaxPoolSize = 10000,
                        PoolTimeoutMs = 2000
                    }).ReusedWithin(ReuseScope.Container);

In the service:

Pool = (RedisManagerPool) GetResolver().TryResolve<IRedisClientsManager>();
            RedisClient = (RedisClient)Pool.GetClient();

....

RedisClient.Dispose();

I also tried disposing the client by using Pool.DisposeClient(RedisClient) in order to return the client back to the pool but I see the same results.

I've also checked the Redis server but no issues in cpu usage, mem usage, 0 refused connections etc.

Can you please let me know if anybody encountered this?

Thank you

Upvotes: 2

Views: 2245

Answers (1)

mythz
mythz

Reputation: 143399

I wouldn't have a pool size that big, keeping 10000 open connections seems worse than not having any connection pooling at all.

You also don't need specify ReuseScope.Container since the default is to use a singleton which is the correct scope for a manager/factory, so I would first try the default configuration:

container.Register<IRedisClientsManager>(c => 
    new RedisManagerPool(Configuration.Config.Instance.RedisConfig.Server));

The Pool Timeout exception suggests that the connection pool has filled up and no connections were free-ed up (i.e. disposed) within the Pool Timeout.

I recommend using the latest v4.0.34 of RedisManagerPool that's on MyGet has a alternate pooling strategy where once the connection pool is full will instead create new unmanaged pool instances instead of locking and throwing after the pool timeout has been reached.

Also in your Service you can access the Redis client using base.Redis since it automatically creates an instance when first accessed and is disposed after the Service is executed, i.e:

public class Service : IDisposable
{
    private IRedisClient redis;
    public virtual IRedisClient Redis
    {
        get { return redis ?? (redis = TryResolve<IRedisClientsManager>().GetClient()); }
    }

    //...

    public virtual void Dispose()
    {
        if (redis != null)
            redis.Dispose();
    }

}

This helps to ensure that the Redis Client is properly disposed of after each request.

Upvotes: 3

Related Questions