Skip to content

Instantly share code, notes, and snippets.

@benhysell
Last active May 14, 2024 02:59
Show Gist options
  • Save benhysell/110deca326edda1c7b16 to your computer and use it in GitHub Desktop.
Save benhysell/110deca326edda1c7b16 to your computer and use it in GitHub Desktop.
c# Redis Caching Objects with StackExchange.Redis using Json
//extension method make a database call by providing a function pointer to Task<T> and passing in a method parameter
public static async Task<T> DatabaseCall<T>(this IDatabase cache, string key, Func<string, Task<T>> databaseCall, string methodParameter, TimeSpan timeSpan, bool invalidate, bool useCache)
{
T returnValue;
var cachedItem = default(T);
try
{
cachedItem = await cache.GetAsync<T>(key);
}
catch (RedisConnectionException ex)
{
//create new connection
HandleRedisConnectionError(ex);
}
if (null != cachedItem && !(cachedItem.Equals(default(T))) && useCache && !invalidate)// != cachedItems && useCache && !invalidate)
{
returnValue = cachedItem;
}
else
{
if (invalidate)
await cache.KeyDeleteAsync(key);
returnValue = await databaseCall(methodParameter);
if (useCache)
await cache.SetAsync(key, returnValue, timeSpan);
}
return returnValue;
}
private static bool attemptingToConnect = false;
private static void HandleRedisConnectionError(RedisConnectionException ex)
{
if (attemptingToConnect) return;
try
{
Policy
.Handle<Exception>()
.WaitAndRetry(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(exception, timeSpan) =>
{
Debug.WriteLine("Redis retry attempt" + exception.Message);
}
)
.Execute(() =>
{
attemptingToConnect = true;
RedisConnection.Reconnect();
});
}
catch (Exception)
{
throw;
}
finally
{
attemptingToConnect = false;
}
}
public static T Get<T>(this IDatabase cache, string key)
{
//return Deserialize<T>(cache.StringGet(key));
try
{
var value = cache.StringGet(key);
if (!value.IsNull)
return JsonConvert.DeserializeObject<T>(value);
else
{
return default(T);
}
}
catch (Exception)
{
throw;
}
}
public static void Set(this IDatabase cache, string key, object value, TimeSpan experation)
{
cache.StringSet(key, JsonConvert.SerializeObject(value), experation);
}
public static async Task SetAsync(this IDatabaseAsync cache, string key, object value, TimeSpan experation)
{
await Policy
.Handle<Exception>()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(exception, timeSpan) =>
{
Debug.WriteLine("Redis retry attempt" + exception.Message);
}
)
.ExecuteAsync(() => cache.StringSetAsync(key, JsonConvert.SerializeObject(value), experation));
}
public static async Task<T> GetAsync<T>(this IDatabaseAsync cache, string key)
{
var result = await Policy
.Handle<RedisConnectionException>()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(exception, timeSpan) =>
{
Debug.WriteLine("Redis retry attempt" + exception.Message);
}
)
.ExecuteAsync(async () =>
{
var value = await cache.StringGetAsync(key);
if (!value.IsNull)
return JsonConvert.DeserializeObject<T>(value);
else
{
return default(T);
}
});
return result;
}
public class RedisConnection
{
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect("localhost"));
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
public static void Reconnect()
{
lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect("localhost"));
}
}
inspired by http://msdn.microsoft.com/en-us/library/azure/dn690521.aspx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment