title: CacheItemPolicy expiration happens only on fixed boundaries
body: <p>Looking for a solution to a FileSystemWatcher issue I found a very interesting solution cited here <a href="https://stackoverflow.com/a/1765094">FileSystemWatcher Changed event is raised twice</a> from the original by <a href="https://failingfast.io/a-robust-solution-for-filesystemwatcher-firing-events-multiple-times/" rel="nofollow noreferrer">Ben Hall</a></p>
  <p>Now, my new problem is about a <code>MemoryCache</code> object with an expiration set by a <code>CacheItemPolicy</code>.</p>
  <p>My final code is almost identical to the example above, besides the class that declares those objects. The confusing result is that the <code>MemoryCache</code> doesn't expire on the time I set with the property <code>MemoryCache.AbsoluteExpiration</code> or <code>MemoryCache.SlidingExpiration</code>, but it does so on a fixed <strong>20 seconds boundary</strong>.</p>
  <p>What I mean is that if I set something like</p>
  <pre><code>    private readonly MemoryCache _memCache = MemoryCache.Default;
      private CacheItemPolicy _cacheItemPolicy = new CacheItemPolicy();
      ...
      private void OnRemoveFromCache(CacheEntryRemovedArguments arguments)
      {
          if (arguments.RemovedReason != CacheEntryRemovedReason.Expired)
              return;
          
          var e = (FileSystemEventArgs)arguments.CacheItem.Value;
          
          //  Process e
          ...
      }
  
      public void Watcher_Changed(object sender, FileSystemEventArgs e)
      {
          _cacheItemPolicy = new()
          {
              RemovedCallback = OnRemoveFromCache,
              AbsoluteExpiration =
                  DateTimeOffset.Now.AddMilliseconds(100.0)
          };
          _memCache.AddOrGetExisting(e.Name, e, _cacheItemPolicy);
      }
  </code></pre>
  <p>the callback <code>OnRemoveFromCache</code> is called <em>only</em> on the seconds :00, :20 or :40</p>
  <p>That is if my event happens at 12:34:05.000 the callback happens at 12:34:20.000, or if the event is at 12:34:23.000 the callback runs at 12:34:40.000</p>
  <p>What is the point I'm missing?</p>
  <p><strong>[EDIT]</strong>
  Oh well, as pointed out by @Alberto, here's <a href="https://failingfast.io/erratic-behaviour-from-net-memorycache-expiration/" rel="nofollow noreferrer">Ben Hall</a> dismantling the previous article by... the same Ben Hall! :D</p>
  <p>And the same from my own little investigation: <code>MemoryCache</code> can only respond with a 20-seconds granularity...</p>
  <p>Next question: is there an alternative with a similar pattern and a finer-grained timer or should I bake it myself? :O</p>