Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deadlock on Async lazy with PublicationOnly

Assume the following code

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        Lazy<TimeSpan> lm = new Lazy<TimeSpan>(GetDataAsync1, System.Threading.LazyThreadSafetyMode.PublicationOnly);

        return new string[] { "value1", "value2", lm.Value.ToString() };
    }

    private TimeSpan GetDataAsync1()
    {

        return GetTS().ConfigureAwait(false).GetAwaiter().GetResult();

    }

    // I Cant change this method, and what is inside it...
    private async Task<TimeSpan> GetTS()
    {
        var sw = Stopwatch.StartNew();

        using (var client = new HttpClient())
        {
            var result = await client.GetAsync("https://www.google.com/");
        }

        sw.Stop();
        return sw.Elapsed;
    }
}

The point is that I am getting some data from remote server, and want to cache that for later use. As remote server may fail in a given point, I dont want to cache exception, but only success result... So keeping than awaiting the value will not work for me

// Cant use this, because this caches failed exception as well
Lazy<Task...> lz = ...
await lz.Value

But above snipped, as expected produce a deadlock, given that I cant change GetTS, is it possible to force Lazy work with my logic?

like image 460
Arsen Mkrtchyan Avatar asked Oct 24 '25 03:10

Arsen Mkrtchyan


1 Answers

The problem actually has nothing to do with Lazy<T>. The deadlock is because it's blocking on asynchronous code.

In this code:

private TimeSpan GetDataAsync1()
{
  return GetTS().ConfigureAwait(false).GetAwaiter().GetResult();
}

the ConfigureAwait(false) does nothing. ConfigureAwait configures awaits, not tasks, and there is no await there.

The best option is to go async all the way. If exceptions are a concern, you can use AsyncLazy<T> and pass AsyncLazyFlags.RetryOnFailure.

If you can't go async all the way, the next best option would be to go synchronous all the way. If you can't do either of these, then you'll have to choose a sync-over-async hack; be aware that there is no hack that works in all situations.

like image 103
Stephen Cleary Avatar answered Oct 25 '25 18:10

Stephen Cleary



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!