public async Task QueryAsync(IClientProxy caller, string rawQuery) { CancelOngoingQuery(out var currentCt); var query = new Query(rawQuery); using (_logger.BeginScope(LogProperties.QueryId, query.Id)) { currentCt.ThrowIfCancellationRequested(); _logger.Verbose("Notifying frontend that query is received."); await caller.InvokeAsync(new QueryReceived(query), currentCt); var providers = GetProviders(query); _logger.Verbose("Notifying frontend that query will be handled by {providerCount} providers.", providers.Count); await caller.InvokeAsync(QueryExecuting.By(providers), currentCt); // Execute query var allTasks = providers.Select(p => Task.Run(async() => { var providerName = p.GetType().Name; using (var operation = _logger.Timed("Query from {queryProvider}", providerName)) { try { var results = (await p.QueryAsync(query, currentCt)).ToList(); currentCt.ThrowIfCancellationRequested(); _logger.Debug("Provider {queryProvider} executed query successfully. {resultCount} results available.", providerName, results.Count); await caller.InvokeAsync(new ResultsAvailable(query.Id, results), currentCt); return(results); } catch (Exception) { operation.Cancel(); throw; } } }, currentCt)) .ToList(); // Wait for provider tasks await Task.WhenAll(allTasks).ContinueWith(async _ => { Task.WaitAll(allTasks.ToArray <Task>()); var allResults = allTasks.Where(t => t.IsCompleted).SelectMany(t => t.Result).ToList(); if (allTasks.Any(t => !t.IsCompletedSuccessfully)) { _logger.Debug("One or more sub queries have failed."); await caller.InvokeAsync(new QueryCancelled(query.Id), currentCt); } else { _logger.Verbose("Query completed. Total result count is {resultCount}", allResults.Count); await caller.InvokeAsync(new QueryCompleted(query.Id, allResults), currentCt); } }); } }
public async Task QueryAsync(string rawQuery, IObserver <BackendEvent> observer) { if (string.IsNullOrWhiteSpace(rawQuery)) { return; } IQuery query = new Query(rawQuery); using (_logger.BeginScope(LogProperties.QueryId, query.Id)) using (_logger.Timed("Query {rawQuery}", rawQuery)) { CancelOngoingQuery(out var currentCt); _logger.Verbose("Notifying observers that query is received."); observer.OnNext(new QueryReceived(query)); var providers = GetProviders(query); if (!providers.Any()) { providers = _queryProviders.ToList(); query = new DefaultQuery(query); } _logger.Verbose("Notifying observers that query will be handled by {providerCount} providers.", providers.Count); observer.OnNext(QueryExecuting.By(providers)); var providerTasks = providers .Select(provider => Task.Run(async() => { var operation = _logger.Timed("{queryProvider} provider", provider.GetType().Name); var providerObserver = Observer.Create <BackendEvent>(observer.OnNext, operation.Cancel, operation.Complete); try { await provider.QueryAsync(query, providerObserver, currentCt); } catch (OperationCanceledException) { _logger.Information("Query {rawQuery} has been cancelled for {queryProvider}", rawQuery, providerObserver.GetType().Name); /* Cancellation is OK */ } catch (Exception e) { _logger.Information(e, "An unhandle exception was thrown."); } finally { providerObserver.OnCompleted(); } }, currentCt)) .ToArray(); await Task.WhenAll(providerTasks); observer.OnNext(new QueryCompleted(query.Id, null)); } }