question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Queries with sync-over-async and synchronization context hang

See original GitHub issue

Describe the bug Continuation of the issue https://github.com/Azure/azure-cosmos-dotnet-v3/issues/1043.

It looks like https://github.com/Azure/azure-cosmos-dotnet-v3/issues/1043 fixed point-read calls, stored procedure calls, calls for db/container details. However, when client does a query with GetItemLinqQueryable<Entity>().ToFeedIterator(), it still hangs.

To Reproduce Repro available in the same repository as previously, https://github.com/lukasz-pyrzyk/CosmosDbSyncOverAsync .

Expected behavior A hang should not occur for query calls

Actual behavior Second query to the database which is called from synchronization context and blocked with .GetAwaiter().GetResult() hangs.

Environment summary SDK Version: 3.5.1 OS Version: Windows 10

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
ealsurcommented, Dec 19, 2019

Checking your original code:

var query = dbClient
    .GetItemLinqQueryable<ClientEntity>(requestOptions: new QueryRequestOptions { PartitionKey = partitionKey })
    .Where(x => x.ClientId == clientId)
    .ToFeedIterator();

var client = await query.ExecuteFirstOrDefault(nameof(GetClient)).ConfigureAwait(false);

public static async Task<TQueryItem> ExecuteFirstOrDefault<TQueryItem>(this FeedIterator<TQueryItem> iterator, string operationName)
{
    Trace.WriteLine($"Executing {operationName}");
    var feedResponse = await iterator.ReadNextAsync().ConfigureAwait(false);
    Trace.WriteLine($"{operationName} finished with status code {feedResponse.StatusCode}. Request charge is {feedResponse.RequestCharge}.");

    return feedResponse.FirstOrDefault();
}

This has the issue that you are not draining the query, which could lead to memory leaking. Since you are already declaring the query as Linq, you can just do:

IQueryable<ClientEntity> query = dbClient.GetItemLinqQueryable<ClientEntity>(
    allowSynchronousQueryExecution: true,
    requestOptions: new QueryRequestOptions()
    {
        PartitionKey = partitionKey
    }).Where(x => x.ClientId == clientId);
    
    var client = query.ToList().FirstOrDefault();

We can check the ReadNextAsync but since there is an alternative for sync scenarios, it is not really a blocker.

0reactions
ealsurcommented, Dec 23, 2019

Can you explain how this can do a memory leaking? Is it a bad pattern to create query, then iterator and call iterator asynchronously?

When you issue a query, you need to loop through the results until HasMoreResults is false, see https://docs.microsoft.com/en-us/azure/cosmos-db/troubleshoot-query-performance#read-all-results-from-continuations (which is for V2 SDK but targets the same scenario). If for whatever reason, there are more results left to read and have been buffered and materialized by the SDK but not consumed, those results will be kept in memory as time passed. As you keep repeating and doing more queries (and not consuming all results), the memory footprint will keep growing.

I agree with the fact that ReadNextAsync should be fixed, I’m just pointing at the fact that it is not urgent when prioritizing versus other work because there is a valid workaround to execute the query (although not ideal, as you pointed out, it does not expose RequestCharge).

Regarding ConfigureAwait, @kirankumarkolli do we have any decision whether we should use ConfigureAwait or not? See https://devblogs.microsoft.com/dotnet/configureawait-faq/

Read more comments on GitHub >

github_iconTop Results From Across the Web

All active requests hang when there is a continuation on ...
So now it looks like it's related to context synchronization. The application is using the old LegacyAspNetSynchronizationContext which does ...
Read more >
Don't Block on Async Code
GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete. The top-level method synchronously blocks on ...
Read more >
ConfigureAwait: is it required?
The UI developer can wait the execution of a method GetTextAsync synchronously (or the code uses a library with a bad, synchronous wait...
Read more >
ASP.NET Core Best Practices
The app does sync over async because Kestrel does NOT support synchronous reads. Do this: The following example uses ReadToEndAsync and does not ......
Read more >
In JavaScript, how is awaiting the result of an async ...
With a synchronous wait, it will look to the user like the page "hangs" while you wait for the network response.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found