@@ -203,26 +203,34 @@ public async ValueTask<T> GetOrSetAsync<T>(string cacheKey, Func<T, Task<T>> get
203203
204204 var currentTime = DateTimeProvider . Now ;
205205 var cacheEntryPoint = await GetWithLayerIndexAsync < T > ( cacheKey ) ;
206- if ( cacheEntryPoint != default && cacheEntryPoint . CacheEntry . Expiry > currentTime )
206+ if ( cacheEntryPoint != default )
207207 {
208- var cacheEntry = cacheEntryPoint . CacheEntry ;
209- if ( settings . StaleAfter . HasValue && cacheEntry . GetStaleDate ( settings ) < currentTime )
208+ if ( cacheEntryPoint . CacheEntry . Expiry > currentTime )
210209 {
211- //If the cache entry is stale, refresh the value in the background
212- _ = RefreshValueAsync ( cacheKey , getter , settings , noExistingValueAvailable : false ) ;
210+ var cacheEntry = cacheEntryPoint . CacheEntry ;
211+ if ( settings . StaleAfter . HasValue && cacheEntry . GetStaleDate ( settings ) < currentTime )
212+ {
213+ //If the cache entry is stale, refresh the value in the background
214+ _ = RefreshValueAsync ( cacheKey , getter , settings , CacheEntryStatus . Stale ) ;
215+ }
216+ else if ( cacheEntryPoint . LayerIndex > 0 )
217+ {
218+ //If a lower-level cache is missing the latest data, attempt to set it in the background
219+ _ = BackPopulateCacheAsync ( cacheEntryPoint . LayerIndex , cacheKey , cacheEntry ) ;
220+ }
221+
222+ return cacheEntry . Value ! ;
213223 }
214- else if ( cacheEntryPoint . LayerIndex > 0 )
224+ else
215225 {
216- //If a lower-level cache is missing the latest data, attempt to set it in the background
217- _ = BackPopulateCacheAsync ( cacheEntryPoint . LayerIndex , cacheKey , cacheEntry ) ;
226+ //Refresh the value in the current thread because we only have expired data (we never return expired data)
227+ return ( await RefreshValueAsync ( cacheKey , getter , settings , CacheEntryStatus . Expired ) ) ! . Value ! ;
218228 }
219-
220- return cacheEntry . Value ! ;
221229 }
222230 else
223231 {
224- //Refresh the value in the current thread though because we have no old cache value, we have to lock and wait
225- return ( await RefreshValueAsync ( cacheKey , getter , settings , noExistingValueAvailable : true ) ) ! . Value ! ;
232+ //Refresh the value in the current thread because we have no existing data
233+ return ( await RefreshValueAsync ( cacheKey , getter , settings , CacheEntryStatus . Miss ) ) ! . Value ! ;
226234 }
227235 }
228236
@@ -264,7 +272,7 @@ private async ValueTask BackPopulateCacheAsync<T>(int fromIndexExclusive, string
264272 }
265273 }
266274
267- private async ValueTask < CacheEntry < T > ? > RefreshValueAsync < T > ( string cacheKey , Func < T , Task < T > > getter , CacheSettings settings , bool noExistingValueAvailable )
275+ private async ValueTask < CacheEntry < T > ? > RefreshValueAsync < T > ( string cacheKey , Func < T , Task < T > > getter , CacheSettings settings , CacheEntryStatus entryStatus )
268276 {
269277 ThrowIfDisposed ( ) ;
270278
@@ -287,7 +295,7 @@ private async ValueTask BackPopulateCacheAsync<T>(int fromIndexExclusive, string
287295 try
288296 {
289297 var previousEntry = await GetAsync < T > ( cacheKey ) ;
290- if ( previousEntry != default && noExistingValueAvailable && previousEntry . Expiry < DateTimeProvider . Now )
298+ if ( previousEntry != default && entryStatus == CacheEntryStatus . Miss && previousEntry . Expiry >= DateTimeProvider . Now )
291299 {
292300 //The Cache Stack will always return an unexpired value if one exists.
293301 //If we are told to refresh because one doesn't and we find one, we return the existing value, ignoring the refresh.
@@ -307,7 +315,11 @@ private async ValueTask BackPopulateCacheAsync<T>(int fromIndexExclusive, string
307315
308316 var value = await getter ( oldValue ! ) ;
309317 var refreshedEntry = new CacheEntry < T > ( value , settings . TimeToLive ) ;
310- var cacheUpdateType = noExistingValueAvailable ? CacheUpdateType . AddEntry : CacheUpdateType . AddOrUpdateEntry ;
318+ var cacheUpdateType = entryStatus switch
319+ {
320+ CacheEntryStatus . Miss => CacheUpdateType . AddEntry ,
321+ _ => CacheUpdateType . AddOrUpdateEntry
322+ } ;
311323 await InternalSetAsync ( cacheKey , refreshedEntry , cacheUpdateType ) ;
312324
313325 UnlockWaitingTasks ( cacheKey , refreshedEntry ) ;
@@ -321,7 +333,7 @@ private async ValueTask BackPopulateCacheAsync<T>(int fromIndexExclusive, string
321333 throw ;
322334 }
323335 }
324- else if ( noExistingValueAvailable )
336+ else if ( entryStatus != CacheEntryStatus . Stale )
325337 {
326338 TaskCompletionSource < CacheEntry > completionSource ;
327339
0 commit comments