patterncsharpMinor
Time Sensitive ConcurrentDictionary
Viewed 0 times
concurrentdictionarysensitivetime
Problem
In our application, we have many function calls that we want to cache the results of. However, the result of these functions depends on database calls, so we want this cache to refresh every so often so that new data is pulled from the database on a regular basis. (Note: we know that these values are changing once a day, so we don't have to refresh the cache very often)
We currently have a caching system in place that stores the results in a
Below is the full code to create a cache
```
public static class FuncUtil_TimeSensitive
{
public static readonly TimeSpan ValidTime = TimeSpan.FromHours(6);
public static Func Memoize(Func f)
{
var map = DictionaryHelper>.CreateConcurrent(new { a = default(A) });
return a => map.GetOrAdd(new { a }, new Lazy(() => f(a))).Value;
}
public static Func Memoize(this Func f)
{
var map = DictionaryHelper>.CreateConcurrent(new { a = default(A), b = default(B) });
return (a, b) => map.GetOrAdd(new { a, b }, new Lazy(() => f(a, b))).Value;
}
//other methods
static class DictionaryHelper
{
public static TimeSensitiveConcurrentDictionary CreateConcurrent(Key prototype)
{
return new TimeSensitiveConcurrentDictionary(ValidTime);
}
}
}
///
/// Stores a value based on the key for a set amoutn of time. After that time has passed, accessing the same key will remove the value
///
/// Type to use as a key
/// Type to use as a value
public class TimeSensitiveConcurrentDictionary
{
private readonly ConcurrentDictionary> cache
= new ConcurrentDictionary>();
private readonly TimeSpan expirationTime;
public TimeSensitiveConcurrentDictionary(Tim
We currently have a caching system in place that stores the results in a
ConcurrentDictionary, so I want to replace that backing with a TimeSensitiveConcurrentDictionary. If the current time is past the expiration time stored for the provided parameters, it will instead return the provided value. In our case, that provided value is a LazyBelow is the full code to create a cache
```
public static class FuncUtil_TimeSensitive
{
public static readonly TimeSpan ValidTime = TimeSpan.FromHours(6);
public static Func Memoize(Func f)
{
var map = DictionaryHelper>.CreateConcurrent(new { a = default(A) });
return a => map.GetOrAdd(new { a }, new Lazy(() => f(a))).Value;
}
public static Func Memoize(this Func f)
{
var map = DictionaryHelper>.CreateConcurrent(new { a = default(A), b = default(B) });
return (a, b) => map.GetOrAdd(new { a, b }, new Lazy(() => f(a, b))).Value;
}
//other methods
static class DictionaryHelper
{
public static TimeSensitiveConcurrentDictionary CreateConcurrent(Key prototype)
{
return new TimeSensitiveConcurrentDictionary(ValidTime);
}
}
}
///
/// Stores a value based on the key for a set amoutn of time. After that time has passed, accessing the same key will remove the value
///
/// Type to use as a key
/// Type to use as a value
public class TimeSensitiveConcurrentDictionary
{
private readonly ConcurrentDictionary> cache
= new ConcurrentDictionary>();
private readonly TimeSpan expirationTime;
public TimeSensitiveConcurrentDictionary(Tim
Solution
-
This class name
-
Bad parameter naming - single letter parameter names are not very descriptive.
-
Lack of documentation - shared general utility classes should have xml doc comments for the class and the public methods.
-
Magic hard coded constant here:
-
I don't really think there is actually a need for the
-
I don't like that you use two
This class name
FuncUtil_TimeSensitive is a bit unusual - FuncUtil sounds like a namespace so you should use a proper namespace rather then prefixing you class name with it.-
Bad parameter naming - single letter parameter names are not very descriptive.
-
Lack of documentation - shared general utility classes should have xml doc comments for the class and the public methods.
-
Magic hard coded constant here:
new TimeSpan(6, 0, 0);- Better would have been to use
TimeSpan.FromHours(6)because then I wouldn't have had to look up what the three parameter constructor was.
- You can't practically unit test this because your unit test would have to sleep for 6 hours before the expiration is hit - this should be a configurable setting with a default value.
-
I don't really think there is actually a need for the
FuncUtil_TimeSensitive helper class - I would have added the factory methods to the TimeSensitiveConcurrentDictionary.-
I don't like that you use two
ConcurrentDictionaries to track two different values for the same key (one for the timeout and one for the actual value). A better way would be to encapsulate that into a member class which is responsible for tracking the timeout.Context
StackExchange Code Review Q#70323, answer score: 3
Revisions (0)
No revisions yet.