Most of the time this function works correctly, but on occasion when trying to execute the statement, RedisKeyType keyType = redisClient.GetEntryType(listID); I get the error āInvalid Valueā. Any ideas?
Calling redisClient.Type(listID) is what is throwing the error. The exception from throw CreateResponseError(āInvalid valueā); statement is the exception Iām getting. The list that is passed in the listID param exists, and even if it doesnāt it shouldnāt throw an exception, should it?
Stack trace is:
at ServiceStack.Redis.RedisNativeClient.GetEntryType(String key)
at ServiceStack.Redis.IRedisClientExtensions.ListExists(RedisClient redisClient, String listID) in C:\...\Extensions\IRedisClientExtensions.cs:line 22
The updated code now throws an error message Invalid Type ā1ā in the same calling code that used to throw Invalid Value that it was supposed to fix
To be clear. Itās in the calling of GetEntryType in the statement:
The change only includes the unknown value in the Exception message, thereās no issue with GetEntryType() implementation which handles all possible values of Redis TYPE command.
The 1 is invalid data for the TYPE command suggesting that the connection is corrupted, typically because the same connection is being shared across multiple threads. Note that only the Redis Client Managers are Thread Safe, the IRedisClient connection can only be used from the Thread that itās resolved with (e.g. using GetClient()) and should be disposed immediately after use, i.e. it should not held in a static variable or maintained as a field in a singleton dependency, etc. The issue would be somewhere else in your code base thatās not managing the Redis Client instances properly.
If you can provide a stand-alone repro I can run locally to reproduce the issue, Iāll be able to determine the cause of the issue.
Why not make all the clients threadsafe by default? Performance overhead?
I think you are correct that not using the threadsafe clients cause the issue. Just need to confirm this.
As per the .NET guidelines and default behaviour, .NET instances especially those wrapping a resource or Network connection like an ADO.NET DB connection or a Socket are not ThreadSafe by default.
If youāre not using an IOC then you can you can store it in a singleton like:
public class RedisConfig
{
public static RedisConfig Instance = new RedisConfig();
public IRedisClientsManager RedisManager { get; set; }
public static IRedisClient GetClient() => Instance.RedisManager.GetClient();
}
The Redis Manager would need to be configured, e.g:
RedisConfig.Instance.RedisManager = new RedisManagerPool(redisHost);
Then your App can resolve clients with:
using (var redis = RedisConfig.GetClient())
{
var type = redis.GetEntryType("MyKeyHere");
}
This looks strange, the redisConfiguration should ideally only be returning a host string, not a RedisClient instance:
newing up the āRedisManagerā here does not workā¦ were you thinking of a different type? Maybe this would be a more general definition that would abstract away the need to use the using block.
public class ThreadSafeRedisInstance
{
public static ThreadSafeRedisInstance Instance = new ThreadSafeRedisInstance();
public RedisManagerPool RedisManager { get; set; }
public static IRedisClient GetClient() => Instance.RedisManager.GetClient();
public static void ExecuteCommand(Action<IRedisClient> actionOnClient)
{
using (var redis = GetClient())
{
actionOnClient(redis);
}
}
public static T ExecuteCommand<T>(Func<IRedisClient, T> actionOnClient)
{
using (var redis = GetClient())
{
T t = actionOnClient(redis);
return t;
}
}
}
Setup would look like:
RedisClient redisClient = redisConfiguration.RedisClient;
ThreadSafeRedisInstance.Instance.RedisManager = new RedisManagerPool(redisClient.Host);