-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
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