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>());
            }
        }
示例#2
0
        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);
        }
示例#4
0
        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);
        }
示例#5
0
 public Task <SearchResult <IPackageSearchMetadata> > RefreshSearchAsync(RefreshToken refreshToken, CancellationToken cancellationToken)
 => Task.FromResult(SearchResult.Empty <IPackageSearchMetadata>());