/// <summary> /// Send out the results for a completed "Get-League-Summary" query /// </summary> /// <param name="queryId"> /// Unique identifier of the query for which we want to send out the results /// </param> /// <param name="log"> /// Trace target for logging the outcomes of this operation /// </param> private static async Task <ActivityResponse> OutputResultsGetLeagueSummaryQuery( string queryName, string queryId, ILogger log) { ActivityResponse ret = new ActivityResponse() { FunctionName = "OutputResultsGetLeagueSummaryQuery" }; Guid queryGuid; if (Guid.TryParse(queryId, out queryGuid)) { // Get the current state of the query... Projection getQueryState = new Projection(@"Query", queryName, queryGuid.ToString(), nameof(Query_Summary_Projection)); if (null != getQueryState) { #region Logging if (null != log) { log.LogDebug($"Projection processor created in OutputResultsGetLeagueSummaryQuery"); } #endregion // Run the query summary projection Query_Summary_Projection qryProjection = new Query_Summary_Projection(log); await getQueryState.Process(qryProjection); if ((qryProjection.CurrentSequenceNumber > 0) || (qryProjection.ProjectionValuesChanged())) { // Process the query state as is now... #region Logging if (null != log) { log.LogDebug($"Query { qryProjection.QueryName } projection run for {queryGuid } in OutputResultsGetLeagueSummaryQuery"); } #endregion // Ignore queries in an invalid state or not yet validated... if (qryProjection.CurrentState == Query_Summary_Projection.QueryState.Invalid) { // No need to run projections on an invalid query #region Logging if (null != log) { log.LogWarning($"Query {queryGuid} state is {qryProjection.CurrentState} so no output processed in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"Query {queryGuid} state is {qryProjection.CurrentState} so no output processed in OutputResultsGetLeagueSummaryQuery"; ret.FatalError = true; return(ret); } // Check all the projections have been run.. Query_Projections_Projection qryProjectionState = new Query_Projections_Projection(log); await getQueryState.Process(qryProjectionState); if ((qryProjectionState.CurrentSequenceNumber > 0) || (qryProjectionState.ProjectionValuesChanged())) { if (qryProjectionState.UnprocessedRequests.Count == 0) { if (qryProjectionState.ProcessedRequests.Count > 0) { // Turn the projections into a query return (This could include a collate step) Get_League_Summary_Definition_Return projectionReturn = new Get_League_Summary_Definition_Return(queryGuid, qryProjectionState.ProcessedRequests[0].AggregateInstanceKey); if (qryProjectionState.ProcessedRequests[0].ProjectionTypeName == typeof(Leagues.League.projection.League_Summary_Information).Name) { Leagues.League.projection.League_Summary_Information projectionResult = ((Newtonsoft.Json.Linq.JObject)qryProjectionState.ProcessedRequests[0].ReturnedValue).ToObject <Leagues.League.projection.League_Summary_Information>(); if (null != projectionResult) { projectionReturn.Location = projectionResult.Location; projectionReturn.Date_Incorporated = projectionResult.Date_Incorporated; projectionReturn.Twitter_Handle = projectionResult.Twitter_Handle; } else { #region Logging if (null != log) { log.LogError($"Unable to convert {qryProjectionState.ProcessedRequests[0].ReturnedValue} to {nameof(Leagues.League.projection.League_Summary_Information)} in OutputResultsGetLeagueSummaryQuery"); } #endregion } } // Get all the output targets Query_Outputs_Projection qryOutputs = new Query_Outputs_Projection(log); await getQueryState.Process(qryOutputs); if ((qryOutputs.CurrentSequenceNumber > 0) || (qryOutputs.ProjectionValuesChanged())) { #region Logging if (null != log) { log.LogDebug($"Sending results to output targets in OutputResultsGetLeagueSummaryQuery"); } #endregion foreach (string location in qryOutputs.Targets.Keys) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - type {qryOutputs.Targets[location]} in OutputResultsGetLeagueSummaryQuery"); } #endregion // Send the output to the location... QueryLogRecord.SendOutput(location, qryOutputs.Targets[location], ret); } ret.Message = $"Sent results to output targets ({qryOutputs.Targets.Keys.Count}) in OutputResultsGetLeagueSummaryQuery"; return(ret); } else { // No outputs set #region Logging if (null != log) { log.LogWarning($"No output targets found in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"No output targets found in OutputResultsGetLeagueSummaryQuery"; return(ret); } } else { // No processed projections found #region Logging if (null != log) { log.LogWarning($"Query {queryGuid} state is has no processed projections so no output processed in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"Query {queryGuid} state is has no processed projections so no output processed in OutputResultsGetLeagueSummaryQuery"; return(ret); } } else { #region Logging if (null != log) { log.LogWarning($"Query {queryGuid} still has unprocessed projections so no output processed in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"Query {queryGuid} still has unprocessed projections so no output processed in OutputResultsGetLeagueSummaryQuery"; return(ret); } } else { ret.Message = $"Projection run but has no results"; ret.FatalError = true; return(ret); } } } } ret.Message = $"Query identifier blank or not set when running OutputResultsGetLeagueSummaryQuery"; ret.FatalError = true; return(ret); }
public static async Task <ActivityResponse> QueryOutputProcessorOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context, Microsoft.Extensions.Logging.ILogger log) { ActivityResponse response = new ActivityResponse() { FunctionName = "QueryOutputProcessorOrchestrator" }; // Get the Query_Outputs_Request from the context... Query_Outputs_Request request = context.GetInput <Query_Outputs_Request>(); if (null != request) { // Read the outputs for the given query Guid queryGuid; if (Guid.TryParse(request.UniqueIdentifier, out queryGuid)) { // Get the current state of the query... Projection getQueryState = new Projection(Constants.Domain_Query, request.QueryName, queryGuid.ToString(), nameof(Query_Summary_Projection)); if (null != getQueryState) { // Get all the output targets Query_Outputs_Projection qryOutputs = new Query_Outputs_Projection(log); await getQueryState.Process(qryOutputs); if ((qryOutputs.CurrentSequenceNumber > 0) || (qryOutputs.ProjectionValuesChanged())) { #region Logging if (null != log) { log.LogDebug($"Sending results to output targets from {request.QueryName} : {request.UniqueIdentifier} "); } #endregion List <Task <ActivityResponse> > allOutputTasks = new List <Task <ActivityResponse> >(); if (null != request.Results) { // Create a QueryOutputRecord<object> QueryOutputRecord <object> outputRequest = QueryOutputRecord <object> .Create(request.Results, @"", request.QueryName, queryGuid); foreach (string location in qryOutputs.WebhookTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being sent by webhook in OutputResultsGetLeagueSummaryQuery"); } #endregion outputRequest.Target = location; // add a task to ouputit it via webhook.... allOutputTasks.Add(context.CallActivityWithRetryAsync <ActivityResponse>("QueryOutputToWebhookActivity", DomainSettings.QueryRetryOptions(), outputRequest)); } foreach (string location in qryOutputs.BlobTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being persisted to a Blob in {response.FunctionName}"); } #endregion outputRequest.Target = location; // add a task to ouputit it via webhook.... allOutputTasks.Add(context.CallActivityWithRetryAsync <ActivityResponse>("QueryOutputToBlobActivity", DomainSettings.QueryRetryOptions(), outputRequest)); } foreach (string location in qryOutputs.ServiceBusTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being sent out via service bus in {response.FunctionName}"); } #endregion outputRequest.Target = location; // add a task to ouputit it via service bus.... allOutputTasks.Add(context.CallActivityWithRetryAsync <ActivityResponse>("QueryOutputToServiceBusActivity", DomainSettings.QueryRetryOptions(), outputRequest)); } //EventGridTargets foreach (string location in qryOutputs.EventGridTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being sent out via event grid in {response.FunctionName}"); } #endregion outputRequest.Target = location; // add a task to ouputit it via event grid.... allOutputTasks.Add(context.CallActivityWithRetryAsync <ActivityResponse>("QueryOutputToEventGridActivity", DomainSettings.QueryRetryOptions(), outputRequest)); } foreach (string location in qryOutputs.SignalRTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being sent out via SignalR in {response.FunctionName}"); } #endregion outputRequest.Target = location; // add a task to ouputit it via SignalR.... allOutputTasks.Add(context.CallActivityWithRetryAsync <ActivityResponse>("QueryOutputToSignalRActivity", DomainSettings.QueryRetryOptions(), outputRequest)); } // TODO: All the other output methods } // Await for all the outputs to have run in parallel... await Task.WhenAll(allOutputTasks); foreach (var returnedResponse in allOutputTasks) { if (returnedResponse.Result.FatalError) { response.FatalError = true; response.Message = returnedResponse.Result.Message; } #region Logging if (null != log) { log.LogDebug($"Sent results to output targets from {returnedResponse.Result.FunctionName} : {returnedResponse.Result.Message } "); } #endregion context.SetCustomStatus(returnedResponse.Result); } } } } } else { response.Message = $"Unable to get outputs request details in sub orchestration {context.InstanceId} "; response.FatalError = true; } return(response); }
/// <summary> /// Send out the results for a completed "Get-League-Summary" query /// </summary> /// <param name="queryId"> /// Unique identifier of the query for which we want to send out the results /// </param> /// <param name="log"> /// Trace target for logging the outcomes of this operation /// </param> private static async Task <ActivityResponse> OutputResultsGetLeagueSummaryQuery( string queryName, string queryId, ILogger log) { ActivityResponse ret = new ActivityResponse() { FunctionName = "OutputResultsGetLeagueSummaryQuery" }; Guid queryGuid; if (Guid.TryParse(queryId, out queryGuid)) { // Get the current state of the query... Projection getQueryState = new Projection(Constants.Domain_Query, queryName, queryGuid.ToString(), nameof(Query_Summary_Projection)); if (null != getQueryState) { #region Logging if (null != log) { log.LogDebug($"Projection processor created in OutputResultsGetLeagueSummaryQuery"); } #endregion // Run the query summary projection Query_Summary_Projection qryProjection = new Query_Summary_Projection(log); await getQueryState.Process(qryProjection); if ((qryProjection.CurrentSequenceNumber > 0) || (qryProjection.ProjectionValuesChanged())) { // Process the query state as is now... #region Logging if (null != log) { log.LogDebug($"Query { qryProjection.QueryName } projection run for {queryGuid } in OutputResultsGetLeagueSummaryQuery"); } #endregion // Ignore queries in an invalid state or not yet validated... if (qryProjection.CurrentState == Query_Summary_Projection.QueryState.Invalid) { // No need to run projections on an invalid query #region Logging if (null != log) { log.LogWarning($"Query {queryGuid} state is {qryProjection.CurrentState} so no output processed in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"Query {queryGuid} state is {qryProjection.CurrentState} so no output processed in OutputResultsGetLeagueSummaryQuery"; ret.FatalError = true; return(ret); } // Check all the projections have been run.. Query_Projections_Projection qryProjectionState = new Query_Projections_Projection(log); await getQueryState.Process(qryProjectionState); if ((qryProjectionState.CurrentSequenceNumber > 0) || (qryProjectionState.ProjectionValuesChanged())) { if (qryProjectionState.UnprocessedRequests.Count == 0) { if (qryProjectionState.ProcessedRequests.Count > 0) { // Turn the projections into a query return (This could include a collate step) Get_League_Summary_Definition_Return projectionReturn = new Get_League_Summary_Definition_Return(queryGuid, qryProjectionState.ProcessedRequests[0].AggregateInstanceKey); if (qryProjectionState.ProcessedRequests[0].ProjectionTypeName == typeof(Leagues.League.projection.League_Summary_Information).Name) { dynamic projectionResult = (qryProjectionState.ProcessedRequests[0].ReturnedValue); if (null != projectionResult) { projectionReturn.Location = projectionResult.Location; projectionReturn.Date_Incorporated = projectionResult.Date_Incorporated; projectionReturn.Twitter_Handle = projectionResult.Twitter_Handle; } else { #region Logging if (null != log) { log.LogError($"Unable to convert {qryProjectionState.ProcessedRequests[0].ReturnedValue} to {nameof(Leagues.League.projection.League_Summary_Information)} in OutputResultsGetLeagueSummaryQuery"); } #endregion } } // Call the outputs processing sub-orchestration // Get all the output targets Query_Outputs_Projection qryOutputs = new Query_Outputs_Projection(log); await getQueryState.Process(qryOutputs); if ((qryOutputs.CurrentSequenceNumber > 0) || (qryOutputs.ProjectionValuesChanged())) { #region Logging if (null != log) { log.LogDebug($"Sending results to output targets in OutputResultsGetLeagueSummaryQuery"); } #endregion foreach (string location in qryOutputs.WebhookTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being sent by webhook in OutputResultsGetLeagueSummaryQuery"); } #endregion if (null != projectionReturn) { var payloadAsJSON = new StringContent(JsonConvert.SerializeObject(projectionReturn)); using (var client = new HttpClient()) { var response = await client.PostAsync(location, payloadAsJSON); if (!response.IsSuccessStatusCode) { ret.Message = $"Failed to send output to {location} webhook - {response.StatusCode} : {response.ReasonPhrase} "; #region Logging if (null != log) { log.LogError($"{ret.FunctionName } : {ret.Message}"); } #endregion } } } } foreach (string location in qryOutputs.EventGridTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being sent by event grid message in OutputResultsGetLeagueSummaryQuery"); } #endregion } foreach (string location in qryOutputs.BlobTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being persisted as a blob in OutputResultsGetLeagueSummaryQuery"); } #endregion } foreach (string location in qryOutputs.DurableFunctionOrchestrationTargets) { #region Logging if (null != log) { log.LogDebug($"Target : { location} - being used to trigger a durable function to wake up in OutputResultsGetLeagueSummaryQuery"); } #endregion } ret.Message = $"Sent results to output targets ({qryOutputs.Targets.Keys.Count}) in OutputResultsGetLeagueSummaryQuery"; return(ret); } else { // No outputs set #region Logging if (null != log) { log.LogWarning($"No output targets found in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"No output targets found in OutputResultsGetLeagueSummaryQuery"; return(ret); } } else { // No processed projections found #region Logging if (null != log) { log.LogWarning($"Query {queryGuid} state is has no processed projections so no output processed in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"Query {queryGuid} state is has no processed projections so no output processed in OutputResultsGetLeagueSummaryQuery"; return(ret); } } else { #region Logging if (null != log) { log.LogWarning($"Query {queryGuid} still has unprocessed projections so no output processed in OutputResultsGetLeagueSummaryQuery"); } #endregion ret.Message = $"Query {queryGuid} still has unprocessed projections so no output processed in OutputResultsGetLeagueSummaryQuery"; return(ret); } } else { ret.Message = $"Projection run but has no results"; ret.FatalError = true; return(ret); } } } } ret.Message = $"Query identifier blank or not set when running OutputResultsGetLeagueSummaryQuery"; ret.FatalError = true; return(ret); }