Sequential requests work fine. But when parallel batch requests are made, it starts giving error for some requests as follow Unexpected reply: *2
I have created PooledRedisClientManager instance using static variable. I can not register and resolve PooledRedisClientManager in container since I have to make multiple instances of PooledRedisClientManager to connect to different redis servers.
dictClientManagers is static dictionary. This is how I’m initializing manager
RedisClientManagerConfig conf = new RedisClientManagerConfig(); conf.DefaultDb = 0; conf.MaxWritePoolSize = 5; conf.MaxReadPoolSize = 5; string[] masters = new string[] { connStringMaster }; string[] slaves = new string[] { connStringSlave1 }; dictClientManagers[redisServerName] = new PooledRedisClientManager(readWriteHosts: masters, readOnlyHosts: slaves, config: conf);
Any help would be really appreciated as It is blocking us to push the code to the production.
Make sure you’re using a ThreadSafe Redis Client Manager and are always retrieving and disposing of the Redis Client in the same thread, are never sharing the RedisClient instance across multiple threads, not storing it in a static property, etc.
You can hold the Thread Safe client managers in a static variable (I.e. they should only be a single instance of them) then all your different threads can access the client manager to resolve their own Redis client instance which they should dispose after they’ve finished using them to get their instance released back into the pool.
The important part is that you’re retrieving and disposing the Redis Client instance which is good. I’d only be changing the defaults if you need to as the Max Pool Size looks really low.
I don’t see value in the additional boilerplate and would just be accessing the Redis Manger directly, e.g:
public static class Redis
{
public static IRedisClientsManager Manager { get; set; }
}
using (var client = Redis.Manager.GetClient())
{
foreach (var item in client.ScanAllHashEntries(redisKey))
{
dictResult.Add(item.Key,item.Value);
}
}
Although my personal preference is to use an IOC to inject the Redis Manager into the classes that need it which will make it more testable.
On a style-note, the .NET Framework design guidelines requires the use of PascalCase for public methods.
I have increased MaxReadPoolSize and MaxWritePoolSize to 20 and tested the load with 10 parallel threads.
Still getting same error. 'Unexpected reply: *2'
I have added additional wrapper to access manager because I need different managers for different kind requests. So that I have to manage one code to access different set of redis servers.
Please add a stand-alone example that we can run locally to see the issue. (e.g. on GitHub)
Note when using any Scan* APIs that return IEnumerable you shouldn’t be consuming it lazily after the client has been disposed (and return back to the pool) as the IEnumerable would still be calling the Redis client that has been returned to the pool. It’s not an issue in your example, just in-case you’re using the Scan APIs elsewhere and consuming it lazily.
The Issue was I was using iterator outside of using clause. I guess client would been disposed/assigned to some other thread. But when iterator tries to read data, it fails to read throwing above mentioned error.