I am trying to fix a method that is supposed to be retrieving arbitrary data from a MemoryCache
using the built-in GetOrCreateAsync
. Here is Microsofts example (from https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-3.0) :
public async Task<IActionResult> CacheGetOrCreateAsynchronous()
{
var cacheEntry = await
_cache.GetOrCreateAsync(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
return View("Cache", cacheEntry);
}
Here is mine:
/// <summary>
/// This deadlocks :(
/// </summary>
/// <param name="dayKey"></param>
/// <returns></returns>
public async Task<IEnumerable<Document>> GetEventsForDay(string dayKey)
{
CheckCacheKeyExists(dayKey);
return await _cache.GetOrCreateAsync(dayKey, async entry =>
{
entry.SetOptions(_cacheEntryOptions);
var events = await EventsForDay(dayKey).ConfigureAwait(false);
return events;
}).ConfigureAwait(false);
}
Where EventsForDay
has a signature of
private async Task<IEnumerable<Document>> EventsForDay(string dayKey)
And all async operations within EventsForDay
are await
and ConfigureAwait(false)
to try prevent deadlocks. However even with those ConfigureAwait(false)
, the async lambda above still deadlocks and never returns.
However, if I use the solution detailed here: https://stackoverflow.com/a/40569410 it no longer deadlocks:
/// <summary>
/// This does not deadlock. Credit here: https://stackoverflow.com/a/40569410
/// </summary>
/// <param name="dayKey"></param>
/// <returns></returns>
public async Task<IEnumerable<Document>> GetEventsForDay(string dayKey)
{
CheckCacheKeyExists(dayKey);
var cachedItem = await Task.Run(async () =>
{
return await _cache.GetOrCreateAsync(dayKey, async entry =>
{
entry.SetOptions(_cacheEntryOptions);
var events = await EventsForDay(dayKey).ConfigureAwait(false);
return events;
}).ConfigureAwait(false);
}).ConfigureAwait(false);
return cachedItem;
}
My questions are:
1.) Why does wrapping my async lambda in a Task.Run
remove the deadlock?
2.) Why does my async lambda deadlock in the first place if the entire call stack after GetEventsForDay
always uses ConfigureAwait(false)
for any await
ed methods in addition to the lambda itself being await
ed with its own ConfigureAwait(false)
?