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 awaited methods in addition to the lambda itself being awaited with its own ConfigureAwait(false)?