I have some services that serve data that is valid only for a limited period of time, is cached for a “short” time and after a relative small period will not be requested. This service memory grows until eat all available memory and stop working.
public class CachedServiceBlahBlah : Service {
[CacheResponse(Duration = 3, LocalCache = true)]
public object Get(GetEvent request) { ... }
}
[Route("/event/{uid}", verbs: "GET"]
public class GetEvent{
public string Uid { get; set; }
public string Var1 { get; set; }
public string Var2 { get; set; }
}
As i see on source (CacheResponseAttribute), is cached with a key composed with the RawUrl, and as is a GET request, the url will be something like “/event/123456789A?Var1=AAAAA&Var2=BBBBB”, correct?.
After the cache expires, the cache entry will remain into memory, and never removed right?
Have I missed something?
Can I configure MemoryCacheClient to flush/remove cache entries when they expire?
Should I code my own MemoryCacheClient class with “auto flush/remove” expired entries?
RTM ENV: Windows, Windows Service, .Net Framework 4.6.2, ServiceStack 5.5
When a expired cache is accessed the MemoryCacheClient should remove the cache entry, if a new cache is created it should override the existing entry. Maybe your events (and cache entries) are all unique and the caches aren’t getting hit? Which doesn’t make it a good candidate for caching.
There’s also an explicit RemoveExpiredEntries() you can resolve from IRequest if needed, e.g:
The events have a short life (90…180 minutes) and change their status every few seconds.
Once dead, they will never be requested again.
Per request may be little “abuse” because it have a lot of requests and already consuming 100% CPU (searching cache items into MemoryCacheClient.memory)
For now, have implemented a MemoryCacheClient class with removing expired every 30 minutes. If necessary I will improve the implementation.
public class AutoRemoveExpiredEntriesMemoryCacheClient : MemoryCacheClient
{
private readonly Timer _removeTimer;
private TimeSpan _removePeriod = TimeSpan.FromMinutes(30);
public AutoRemoveExpiredEntriesMemoryCacheClient() : base()
{
_removeTimer = new Timer((_) => RemoveExpiredEntries(), null, _removePeriod, _removePeriod);
}
public bool AutoRemoveActive => _removePeriod == TimeSpan.Zero;
public TimeSpan RemovePeriod
{
get
{
return _removePeriod;
}
set
{
if (value <= TimeSpan.Zero)
{
_removePeriod = TimeSpan.Zero;
_removeTimer.Change(-1, -1);
}
else
{
_removePeriod = value;
_removeTimer.Change(_removePeriod, _removePeriod);
}
}
}
}