private async Task LoadNextAsync() { var searchResult = await _searchTask; while (searchResult.RefreshToken != null) { searchResult = await _packageFeed.RefreshSearchAsync(searchResult.RefreshToken, _cancellationToken); } _current = searchResult.GetEnumerator(); foreach (var pair in searchResult.SourceSearchException) { _handleException(pair.Key, pair.Value); } if (searchResult.NextToken != null) { _searchTask = _packageFeed.ContinueSearchAsync(searchResult.NextToken, _cancellationToken); } else { _searchTask = Task.FromResult(SearchResult.Empty <IPackageSearchMetadata>()); } }
private async Task <SearchResult <IPackageSearchMetadata> > AggregateSearchResultsAsync( string searchText, IEnumerable <SearchResult <IPackageSearchMetadata> > results, TelemetryState telemetryState) { SearchResult <IPackageSearchMetadata> result; var nonEmptyResults = results.Where(r => r.Any()).ToArray(); if (nonEmptyResults.Length == 0) { result = SearchResult.Empty <IPackageSearchMetadata>(); } else if (nonEmptyResults.Length == 1) { result = SearchResult.FromItems(nonEmptyResults[0].Items); } else { var items = nonEmptyResults.Select(r => r.Items).ToArray(); var indexer = new RelevanceSearchResultsIndexer(); var aggregator = new SearchResultsAggregator(indexer, new PackageSearchMetadataSplicer()); var aggregatedItems = await aggregator.AggregateAsync( searchText, items); result = SearchResult.FromItems(aggregatedItems.ToArray()); // set correct count of unmerged items result.RawItemsCount = items.Aggregate(0, (r, next) => r + next.Count); } result.SourceSearchStatus = results .SelectMany(r => r.SourceSearchStatus) .ToDictionary(kv => kv.Key, kv => kv.Value); var cursors = results .Where(r => r.NextToken != null) .ToDictionary(r => r.SourceSearchStatus.Single().Key, r => r.NextToken); if (cursors.Keys.Any()) { result.NextToken = new AggregatedContinuationToken { TelemetryState = telemetryState, SearchString = searchText, SourceSearchCursors = cursors }; } return(result); }
private async Task <SearchResult <IPackageSearchMetadata> > WaitForCompletionOrBailOutAsync( string searchText, IDictionary <string, Task <SearchResult <IPackageSearchMetadata> > > searchTasks, CancellationToken cancellationToken) { if (searchTasks.Count == 0) { return(SearchResult.Empty <IPackageSearchMetadata>()); } var aggregatedTask = Task.WhenAll(searchTasks.Values); RefreshToken refreshToken = null; if (aggregatedTask != await Task.WhenAny(aggregatedTask, Task.Delay(DefaultTimeout))) { refreshToken = new AggregatedRefreshToken { SearchString = searchText, SearchTasks = searchTasks, RetryAfter = DefaultTimeout }; } var partitionedTasks = searchTasks .ToLookup(t => t.Value.Status == TaskStatus.RanToCompletion); var completedOnly = partitionedTasks[true]; SearchResult <IPackageSearchMetadata> aggregated; if (completedOnly.Any()) { var results = await Task.WhenAll(completedOnly.Select(kv => kv.Value)); aggregated = await AggregateSearchResultsAsync(searchText, results); } else { aggregated = SearchResult.Empty <IPackageSearchMetadata>(); } aggregated.RefreshToken = refreshToken; var notCompleted = partitionedTasks[false]; if (notCompleted.Any()) { var statuses = notCompleted.ToDictionary( kv => kv.Key, kv => GetLoadingStatus(kv.Value.Status)); foreach (var item in statuses) { aggregated.SourceSearchStatus.Add(item); } var exceptions = notCompleted .Where(kv => kv.Value.Exception != null) .ToDictionary( kv => kv.Key, kv => (Exception)kv.Value.Exception); foreach (var item in exceptions) { aggregated.SourceSearchException.Add(item); } } return(aggregated); }
private async Task <SearchResult <IPackageSearchMetadata> > WaitForCompletionOrBailOutAsync( string searchText, IDictionary <string, Task <SearchResult <IPackageSearchMetadata> > > searchTasks, TelemetryState telemetryState, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (searchTasks.Count == 0) { return(SearchResult.Empty <IPackageSearchMetadata>()); } var aggregatedTask = Task.WhenAll(searchTasks.Values); RefreshToken refreshToken = null; if (aggregatedTask != await Task.WhenAny(aggregatedTask, Task.Delay(DefaultTimeout))) { refreshToken = new AggregatedRefreshToken { TelemetryState = telemetryState, SearchString = searchText, SearchTasks = searchTasks, RetryAfter = DefaultTimeout }; } var partitionedTasks = searchTasks .ToLookup(t => t.Value.Status == TaskStatus.RanToCompletion); var completedOnly = partitionedTasks[true]; SearchResult <IPackageSearchMetadata> aggregated; IEnumerable <TimeSpan> timings = null; var timeAggregation = new Stopwatch(); if (completedOnly.Any()) { var results = await Task.WhenAll(completedOnly.Select(kv => kv.Value)); timings = results.Select(e => e.Duration); timeAggregation.Start(); aggregated = await AggregateSearchResultsAsync(searchText, results, telemetryState); timeAggregation.Stop(); } else { timings = Enumerable.Empty <TimeSpan>(); aggregated = SearchResult.Empty <IPackageSearchMetadata>(); } aggregated.OperationId = telemetryState?.OperationId; aggregated.RefreshToken = refreshToken; var notCompleted = partitionedTasks[false]; if (notCompleted.Any()) { var statuses = notCompleted.ToDictionary( kv => kv.Key, kv => GetLoadingStatus(kv.Value.Status)); foreach (var item in statuses) { aggregated.SourceSearchStatus.Add(item); } var exceptions = notCompleted .Where(kv => kv.Value.Exception != null) .ToDictionary( kv => kv.Key, kv => (Exception)kv.Value.Exception); foreach (var item in exceptions) { aggregated.SourceSearchException.Add(item); } } if (_telemetryService != null && aggregated.SourceSearchStatus != null && aggregated.SourceSearchStatus.Values != null && telemetryState != null) { var loadingStatus = aggregated.SourceSearchStatus.Values.Aggregate(); if (loadingStatus != LoadingStatus.Loading && telemetryState.ShouldEmit) { telemetryState.Duration.Stop(); _telemetryService.EmitTelemetryEvent(new SearchPageTelemetryEvent( telemetryState.OperationId, telemetryState.PageIndex, aggregated.Items?.Count ?? 0, telemetryState.Duration.Elapsed, timings, timeAggregation.Elapsed, loadingStatus)); } } return(aggregated); }
public Task <SearchResult <IPackageSearchMetadata> > RefreshSearchAsync(RefreshToken refreshToken, CancellationToken cancellationToken) => Task.FromResult(SearchResult.Empty <IPackageSearchMetadata>());