When UseStreaming(true), cancellationToken doesn't cancel the query

When using the streaming setting, cancellationToken doesn’t work; the query continues to run. If I comment out the UseStreaming(true), cancellationToken works fine; the long running query disappears from Query Monitor. How is this supposed to work?

.
.
var query = QueryRequest.Create(queryString);
query.UseStreaming(true);
var queryResult = this.Bucket.QueryAsync(query, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
.
.

@dsullivan -

It may be a bug; note that with streaming the HTTP request stream is passed to the IQueryResult impl without closing it. When you iterate on the IQueryResult (which implements IEnumerable) each row is read and deserialized one at a time. When its false, the entire response stream is read into memory and the results converted to type T and stored in a list before passing it to the IQueryResult impl.

In both cases, the token is passed to the HTTPClient , however streaming uses SendAsync and non-streaming uses PostAsync.

Is there any way to force the query to cancel using the QueryResult? or any other work around?

@jmorris -
Is there any way to force the query to cancel using the QueryResult? or any other work around?

@dsullivan

Sorry to jump in here, but I believe @jmorris is out today.

I would try calling Dispose on the IQueryResult if you need to cancel during your iteration of the result stream. Something like this (using will cause Dispose):

using (var result = bucket.Query<MyType>(query, cancellationToken))
{
    result.EnsureSuccess();

    foreach (var item in result) {
        if (cancellationToken.IsCancellationRequested)
        {
            break;
        }

        // Do work 
    } 

    // When streaming, errors can occur after the  data, so check again
    result.EnsureSuccess();
}

Disclaimer: Syntax may not be right, just wrote this from memory in the post.

2 Likes

@btburnett3
Thanks for the input. This only works some of the time. Could there be anything missing from the sample code you provided?

@dsullivan

If that still doesn’t work then I’m uncertain what the problem would be. Disposing the response disposes the HttpResponse stream, which I would think should cancel the ongoing HTTP request by closing the socket. It might be an issue within .NET’s HttpClient, or could be a bug in the SDK, or something else entirely. Do you have any way to trace the HTTP request, perhaps with Fiddler, and see if it’s consistently being closed by the client?

@dsullivan -

The StreamingQueryResult returned when UseStreaming is set to true implements the IDisposable interface; casting to IDisposable or StreamingQueryResult will allow you to call Dispose() which then closes the underlying stream.

@jmorris @btburnett3 -

As I’ve discovered… just calling .Dispose() on the IDisposable Iterator will not always work. The method that is calling bucket.Query(…) (which is wrapped in a using statement like @btburnett3 shows above ) is returning an Iterator (yield return) to the api controller level; that Iterator (rather than just calling .Dispose() on it) also needs to be wrapped in a using statement at the api controller level. I did finally get this to work.
Thanks for your help.

1 Like