Skip to content

[BUG] Incorrect behavior for SearchAsyncClient.search() with multiple subscribers #43095

@dconnelly

Description

@dconnelly

Describe the bug
The SearchAsyncClient.search() method has a bug where the first page result for the initial subscriber is shared by subsequent subscribers. This prevents the search request from being re-sent for additional subscribers.

Exception or Stack Trace
N/A

To Reproduce
Create an async search request and subscribe to it more than once.

Code Snippet
From com.azure.search.documents.SearchAsyncClient, you can see that SearchFirstPageResponseWrapper is mutable state shared by all subscribers:

@ServiceMethod(returns = ReturnType.COLLECTION)
public SearchPagedFlux search(String searchText, SearchOptions searchOptions) {
    SearchRequest request = createSearchRequest(searchText, searchOptions);
    // The firstPageResponse shared among all functional calls below.
    // Do not initial new instance directly in func call.
    final SearchFirstPageResponseWrapper firstPageResponse = new SearchFirstPageResponseWrapper();
    Function<String, Mono<SearchPagedResponse>> func = continuationToken -> withContext(
        context -> search(request, continuationToken, firstPageResponse, context));
    return new SearchPagedFlux(() -> func.apply(null), func);
}

A bit further down, you can see how func will call setFirstPageResponse() on the wrapper after sending the first request, but when subscribed again will simply return that result rather than send the search request again:

private Mono<SearchPagedResponse> search(SearchRequest request, String continuationToken,
    SearchFirstPageResponseWrapper firstPageResponseWrapper, Context context) {
    if (continuationToken == null && firstPageResponseWrapper.getFirstPageResponse() != null) {
        return Mono.just(firstPageResponseWrapper.getFirstPageResponse());  // First subscriber response always returned here
    }
    SearchRequest requestToUse = (continuationToken == null)
        ? request
        : SearchContinuationToken.deserializeToken(serviceVersion.getVersion(), continuationToken);

    return restClient.getDocuments()
        .searchPostWithResponseAsync(requestToUse, null, context)
        .onErrorMap(MappingUtils::exceptionMapper)
        .map(response -> {
            SearchDocumentsResult result = response.getValue();

            SearchPagedResponse page
                = new SearchPagedResponse(new SimpleResponse<>(response, getSearchResults(result, serializer)),
                    createContinuationToken(result, serviceVersion), result.getFacets(), result.getCount(),
                    result.getCoverage(), result.getAnswers(), result.getSemanticPartialResponseReason(),
                    result.getSemanticPartialResponseType());
            if (continuationToken == null) {
                firstPageResponseWrapper.setFirstPageResponse(page); // First subscriber response set here
            }
            return page;
        });
}

Subsequent subscribers will always receive the first page "cached" for the first subscriber. To prevent this each subscriber should have its own pagination state.

Expected behavior
Response state should not be shared and reused between subscribers.

Screenshots
N/A

Setup (please complete the following information):

  • OS: macOS
  • IDE: IntelliJ
  • Library/Libraries: com.azure:azure-search-documents:11.7.3
  • Java version: 21
  • App Server/Environment: JAX-RS
  • Frameworks: Dropwizard 2.x

Additional context
N/A

Information Checklist
Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report

  • Bug Description Added
  • Repro Steps Added
  • Setup information Added

Metadata

Metadata

Labels

ClientThis issue points to a problem in the data-plane of the library.SearchbugThis issue requires a change to an existing behavior in the product in order to be resolved.customer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK team

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions