Reputation: 15323
I noticed that the ASP.NET cache items are inspected (and possibly removed) every 20 seconds (and oddly enough each time at HH:MM:00, HH:MM:20 and HH:MM:40). I spent about 15 minutes looking how to change this parameter without any success. I also tried to set the following in web.config, but it did not help:
<cache privateBytesPollTime="00:00:05" />
I’m not trying to do anything crazy, but it would be nice if it was, say, 5 seconds instead of 20, or at least 10 for my application.
Upvotes: 14
Views: 4284
Reputation: 21
Crazy, but working solution (all steps are needed):
// New value for cache expiration cycle
// System.Web.Caching.CacheExpires._tsPerBucket;
// Set 1 seconds instead of 20sec
const string assembly = "System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
var type = Type.GetType("System.Web.Caching.CacheExpires, " + assembly, true, true);
var field = type.GetField("_tsPerBucket", BindingFlags.Static | BindingFlags.NonPublic);
field.SetValue(null, TimeSpan.FromSeconds(1));
// Recreate cache
// HttpRuntime._theRuntime._cacheInternal = null;
// HttpRuntime._theRuntime._cachePublic = null;
type = typeof (HttpRuntime);
field = type.GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
var runtime = field.GetValue(null);
field = type.GetField("_cachePublic", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(runtime, null);
field = type.GetField("_cacheInternal", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(runtime, null);
Upvotes: 2
Reputation: 12093
Poking around with Reflector reveals that the the interval is hardcoded. Expiry is handled by an internal CacheExpires
class, whose static constructor contains
_tsPerBucket = new TimeSpan(0, 0, 20);
_tsPerBucket
is readonly
, so there can't be any configuration setting that modifies it later.
The timer that will trigger the check for expired items is then set up in CacheExpires.EnableExpirationTimer()
...
DateTime utcNow = DateTime.UtcNow;
TimeSpan span = _tsPerBucket - new TimeSpan(utcNow.Ticks % _tsPerBucket.Ticks);
this._timer = new Timer(new TimerCallback(this.TimerCallback), null,
span.Ticks / 0x2710L, _tsPerBucket.Ticks / 0x2710L);
The calculation of span
ensures that the timer fires exactly on :00, :20, :40 seconds, though I can't see any reason to bother. The method that the timer calls is internal
, so I don't think there's any way to set up your own timer to call it more often (ignoring reflection).
However, the good news is that you shouldn't really have any reason to care about the interval. Cache.Get()
checks that the item hasn't expired, and if it has then it removes the item from the cache immediately and returns null
. Therefore you'll never get an expired item from the cache, even though expired items may stay in the cache for up to 20 seconds.
Upvotes: 21
Reputation: 34810
According to the documentation, privateBytesPollTime is for "worker process memory usage" and the default is 1 second. I don't think this relates to cache item removal.
I did confirm your results using an item removal callback- it looks like items are removed at the bottom of the minute, :20, and :40 seconds. This suggests that an item may remain in the cache for up to 20 seconds past the AbsoluteExpiration set on them. I couldn't find any documentation stating whether the 20 second polling interval could be changed.
Upvotes: 2