/// <summary> /// Query the reliable collection with the given name from the reliable state manager using the given query parameters. /// </summary> /// <param name="stateManager">Reliable state manager for the replica.</param> /// <param name="serviceContext">Stateful Service Context.</param> /// <param name="collection">Name of the reliable collection.</param> /// <param name="query">OData query parameters.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The json serialized results of the query.</returns> public static async Task <IEnumerable <JToken> > QueryAsync(this IReliableStateManager stateManager, StatefulServiceContext serviceContext, HttpContext httpContext, string collection, IEnumerable <KeyValuePair <string, string> > query, bool isStandaloneReplica, CancellationToken cancellationToken) { // Get the list of partitions (excluding the executing partition). var partitions = Enumerable.Empty <Partition>(); if (!isStandaloneReplica) { partitions = await StatefulServiceUtils.GetPartitionsAsync(serviceContext).ConfigureAwait(false); } // Query all service partitions concurrently. var remoteQueries = partitions.Select(p => QueryPartitionAsync(p, serviceContext, collection, query, cancellationToken)); var localQuery = stateManager.QueryPartitionAsync(httpContext, collection, query, serviceContext.PartitionId, cancellationToken); var queries = remoteQueries.Concat(new[] { localQuery }); // Aggregate all query results into a single list. var queryResults = await Task.WhenAll(queries).ConfigureAwait(false); var results = queryResults.SelectMany(r => r); // Run the aggregation query to get the final results (e.g. for top, orderby, project). var reliableState = await stateManager.GetQueryableState(httpContext, collection).ConfigureAwait(false); var entityType = reliableState.GetEntityType(); var objects = results.Select(r => r.ToObject(entityType)); var queryResult = ApplyQuery(objects, entityType, query, aggregate: true); results = queryResult.Select(q => JObject.FromObject(q)); // Return the filtered data as json. return(results); }
/// <summary> /// This implementation should not leak into the core Queryable code. It is dependent on the specific protocol /// used to communicate with the other partitions (HTTP over ReverseProxy), and should be hidden behind an interface. /// </summary> private static async Task <IEnumerable <JToken> > QueryPartitionAsync(Partition partition, StatefulServiceContext context, string collection, IEnumerable <KeyValuePair <string, string> > query, CancellationToken cancellationToken) { string endpoint = await StatefulServiceUtils.GetPartitionEndpointAsync(context, partition).ConfigureAwait(false); string content = await StatefulServiceUtils.QueryPartitionAsync(endpoint, partition.PartitionInformation.Id, collection, query).ConfigureAwait(false); var result = JsonConvert.DeserializeObject <ODataResult>(content); return(result.Value); }