Skip to content

NCO-57: Async Analytics Query#59

Merged
davidkelly merged 7 commits into
masterfrom
dk/nco57
Apr 28, 2026
Merged

NCO-57: Async Analytics Query#59
davidkelly merged 7 commits into
masterfrom
dk/nco57

Conversation

@davidkelly
Copy link
Copy Markdown
Collaborator

The spec changed a bit, so we refactored our existing unreleased code accordingly.

  • Add new QueryStatus class as an intermediate between QueryHandle and QueryResultHandle, replacing the nullable QueryResultHandle? polling pattern with ResultsReady/ResultHandle() per EA-4 spec
  • Rename FetchResultHandleAsync to FetchStatusAsync across QueryHandle, IAnalyticsService, and AnalyticsService
  • Rename FetchResultHandleOptions to FetchStatusOptions
  • Make QueryHandle.Handle and QueryHandle.RequestId internal
  • Add ProcessedObjects to AsyncQueryMetrics
  • Enrich QueryStatus.ToString() with all available server response fields (resultCount, resultSetOrdered, partitions, createdAt, metrics) with resilient handling when fields are absent
  • Update all unit tests, functional tests, and test helpers

The spec changed a bit, so we refactored our existing unreleased
code accordingly.

- Add new QueryStatus class as an intermediate between QueryHandle and
  QueryResultHandle, replacing the nullable QueryResultHandle? polling
  pattern with ResultsReady/ResultHandle() per EA-4 spec
- Rename FetchResultHandleAsync to FetchStatusAsync across QueryHandle,
  IAnalyticsService, and AnalyticsService
- Rename FetchResultHandleOptions to FetchStatusOptions
- Make QueryHandle.Handle and QueryHandle.RequestId internal
- Add ProcessedObjects to AsyncQueryMetrics
- Enrich QueryStatus.ToString() with all available server response
  fields (resultCount, resultSetOrdered, partitions, createdAt, metrics)
  with resilient handling when fields are absent
- Update all unit tests, functional tests, and test helpers
@davidkelly davidkelly requested a review from emilienbev April 22, 2026 03:49
@davidkelly davidkelly marked this pull request as ready for review April 22, 2026 03:49
@emilienbev emilienbev requested a review from Copilot April 22, 2026 10:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the async analytics query workflow to match the updated EA-4 spec by introducing a QueryStatus intermediate type, renaming the polling API from “result handle” to “status”, and updating result/streaming behaviors plus related tests.

Changes:

  • Introduces QueryStatus with ResultsReady + ResultHandle() and richer ToString() diagnostics.
  • Renames FetchResultHandleAsyncFetchStatusAsync (and associated options types) across service/handles and updates tests accordingly.
  • Adds async disposal support for query results and adjusts streaming enumeration behavior (including new unit tests).

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Couchbase.Analytics.UnitTests/Internal/StreamingAnalyticsResultTests.cs Adds coverage for single-enumeration behavior and async disposal.
tests/Couchbase.Analytics.UnitTests/Internal/ExecuteQueryTests.cs Updates test shim to implement IAsyncDisposable on IQueryResult.
tests/Couchbase.Analytics.UnitTests/Internal/AnalyticsServiceTests.cs Renames test to FetchStatusAsync and updates options types.
tests/Couchbase.Analytics.UnitTests/Helpers/TestHandleFactory.cs Adds CreateQueryStatus helper for new async status type.
tests/Couchbase.Analytics.UnitTests/Async/QueryStatusTests.cs New unit tests validating QueryStatus parsing, readiness, and ToString().
tests/Couchbase.Analytics.UnitTests/Async/QueryHandleTests.cs Updates handle tests to delegate via FetchStatusAsync.
tests/Couchbase.Analytics.FunctionalTests/Internal/CouchbaseHttpClientTests.cs Updates result iteration to use result.Rows.
tests/Couchbase.Analytics.FunctionalTests/Internal/AnalyticsServiceTests.cs Updates result iteration to use result.Rows.
tests/Couchbase.Analytics.FunctionalTests/AsyncAnalyticsTests.cs Updates end-to-end async polling to use QueryStatus + ResultsReady.
src/Couchbase.Analytics/Results/IQueryResult.cs Extends IQueryResult with IAsyncDisposable.
src/Couchbase.Analytics/Query/AsyncQueryMetrics.cs Adds ProcessedObjects for async-query metrics deserialization.
src/Couchbase.Analytics/Options/FetchStatusOptions.cs Renames options record and updates docs to “status”.
src/Couchbase.Analytics/Internal/Results/StreamingAnalyticsResult.cs Changes second enumeration behavior to throw an exception.
src/Couchbase.Analytics/Internal/Results/AnalyticsResultBase.cs Adds DisposeAsync() implementation for results.
src/Couchbase.Analytics/Internal/IAnalyticsService.cs Renames service polling method to FetchStatusAsync returning QueryStatus.
src/Couchbase.Analytics/Internal/AnalyticsService.cs Implements FetchStatusAsync, clones parsed JSON, updates logging and error handling.
src/Couchbase.Analytics/Async/QueryStatus.cs Adds new status type with parsing, readiness logic, and diagnostics.
src/Couchbase.Analytics/Async/QueryHandle.cs Makes handle/requestId internal and renames polling API to FetchStatusAsync.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Couchbase.Analytics/Internal/Results/StreamingAnalyticsResult.cs Outdated
Comment thread src/Couchbase.Analytics/Internal/Results/AnalyticsResultBase.cs
Comment thread tests/Couchbase.Analytics.UnitTests/Helpers/TestHandleFactory.cs Outdated
Comment thread src/Couchbase.Analytics/Internal/AnalyticsService.cs
Comment thread src/Couchbase.Analytics/Internal/AnalyticsService.cs
@davidkelly
Copy link
Copy Markdown
Collaborator Author

@copilot review

- result disposal safer
- thread-safe enumeration guard throughout
- non-JSON responses handled without exception
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

src/Couchbase.Analytics/Internal/Results/StreamingAnalyticsResult.cs:76

  • EnumerateRows marks the result as already enumerated before verifying initialization (_hasReadToResult). If a consumer accidentally enumerates before calling InitializeAsync, this will permanently flip _enumerated and subsequent (correct) enumeration after initialization will always throw. Consider moving the Interlocked.CompareExchange check to after the initialization guard so a pre-initialize call fails without consuming the one-time enumeration slot.
        if (Interlocked.CompareExchange(ref _enumerated, 1, 0) != 0)
        {
            throw new InvalidOperationException(
                "Query results can only be enumerated once. The result stream has already been consumed.");
        }

        if (!_hasReadToResult)
        {
            throw new InvalidOperationException(
                $"{nameof(StreamingAnalyticsResult)} has not been initialized, call InitializeAsync first");
        }

src/Couchbase.Analytics/Internal/AnalyticsService.cs:344

  • FetchStatusAsync creates a short-lived HttpClient via CreateHttpClient(timeout) but never disposes it. ICouchbaseHttpClientFactory.Create() is documented as producing a client intended to be disposed after use; polling this endpoint can create many clients and increase memory/socket pressure. Dispose the HttpClient in this method (e.g., via using/await using or a try/finally).
        var timeout = _clusterOptions.TimeoutOptions.DispatchTimeout;
        var httpClient = CreateHttpClient(timeout);


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Couchbase.Analytics/Internal/AnalyticsService.cs Outdated
…hods

Fix enumeration guard ordering in StreamingAnalyticsResult
@davidkelly davidkelly requested a review from jeffrymorris April 27, 2026 19:49
Copy link
Copy Markdown
Contributor

@jeffrymorris jeffrymorris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@davidkelly davidkelly merged commit 11ae046 into master Apr 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants