public static async Task <List <Query_Projections_Projection_Return> > GetQueryProjectionsStatusProjectionActivity( [ActivityTrigger] DurableActivityContext context, ILogger log ) { Query_Projections_Projection_Request queryInfo = context.GetInput <Query_Projections_Projection_Request>(); #region Logging if (null != log) { log.LogInformation($"GetQueryProjectionsStatusProjectionActivity called for query ID: {queryInfo.UniqueIdentifier }"); } #endregion return(await ProcessQueryProjectionsStatusProjection( queryInfo.QueryName, queryInfo.UniqueIdentifier, log)); }
public static async Task <Get_League_Summary_Definition_Return> OnGetLeagueSummaryQueryHandlerOrchestrator ([OrchestrationTrigger] DurableOrchestrationContext context, Microsoft.Extensions.Logging.ILogger log) { // Get the query definition form the context... QueryRequest <Get_League_Summary_Definition> queryRequest = context.GetInput <QueryRequest <Get_League_Summary_Definition> >(); try { if (null != queryRequest) { if (string.IsNullOrWhiteSpace(queryRequest.QueryName)) { queryRequest.QueryName = "Get League Summary"; } // Log the query request in its own own query event stream Guid queryId = await context.CallActivityWithRetryAsync <Guid>("GetLeagueSummaryCreateQueryRequestActivity", DomainSettings.QueryRetryOptions(), queryRequest); if (queryId.Equals(Guid.Empty)) { #region Logging if (null != log) { // Unable to get the request details from the orchestration log.LogError("OnGetLeagueSummaryQueryHandlerOrchestrator : Unable to create the query event stream"); } #endregion return(null); } else { queryRequest.QueryUniqueIdentifier = queryId; // Save the parameters to the event stream ActivityResponse resp = null; resp = await context.CallActivityWithRetryAsync <ActivityResponse>("GetLeagueSummaryLogParametersActivity", DomainSettings.QueryRetryOptions(), queryRequest); #region Logging if (null != log) { if (null != resp) { log.LogInformation($"{resp.FunctionName} complete: {resp.Message } "); } } #endregion if (null != resp) { context.SetCustomStatus(resp); } // next validate the query bool valid = false; try { valid = await context.CallActivityWithRetryAsync <bool>("GetLeagueSummaryValidateActivity", DomainSettings.QueryRetryOptions(), queryRequest); } catch (FunctionFailedException ffs) { if (null == resp) { resp = new ActivityResponse() { FunctionName = "QueryProjectionProcessorOrchestrator" }; } resp.Message = ffs.Message; resp.FatalError = true; } if (!valid) { #region Logging if (null != log) { // Could not run the query as the parameters don't make sense log.LogError($"OnGetLeagueSummaryQueryHandlerOrchestrator : Query parameters are invalid {queryId}"); } #endregion return(null); } else { try { // Request all the projections needed to answer this query resp = await context.CallActivityWithRetryAsync <ActivityResponse>("GetLeagueSummaryQueryProjectionRequestActivity", DomainSettings.QueryRetryOptions(), queryRequest); } catch (FunctionFailedException ffs) { if (null == resp) { resp = new ActivityResponse() { FunctionName = "QueryProjectionProcessorOrchestrator" }; } resp.Message = ffs.Message; resp.FatalError = true; } if (null != resp) { #region Logging if (null != log) { if (null != resp) { log.LogInformation($"{resp.FunctionName} complete: {resp.Message } "); } } #endregion context.SetCustomStatus(resp); if (resp.FatalError) { #region Logging if (null != log) { log.LogError($"Fatal error in {resp.FunctionName} - {resp.Message} "); } #endregion return(null); } } // Get all the outstanding projection requests by calling a sub-orchestrator Query_Projections_Projection_Request projectionQueryRequest = new Query_Projections_Projection_Request() { UniqueIdentifier = queryRequest.QueryUniqueIdentifier.ToString(), QueryName = queryRequest.QueryName }; try { resp = await context.CallSubOrchestratorWithRetryAsync <ActivityResponse>("QueryProjectionProcessorOrchestrator", DomainSettings.QueryRetryOptions(), projectionQueryRequest); } catch (FunctionFailedException ffs) { if (null == resp) { resp = new ActivityResponse() { FunctionName = "QueryProjectionProcessorOrchestrator" }; } resp.Message = ffs.Message; resp.FatalError = true; } if (null != resp) { #region Logging if (null != log) { if (null != resp) { log.LogInformation($"{resp.FunctionName} complete: {resp.Message } "); } } #endregion context.SetCustomStatus(resp); if (resp.FatalError) { #region Logging if (null != log) { log.LogError($"Fatal error in {resp.FunctionName} - {resp.Message} "); } #endregion return(null); } } try { // Output the results resp = await context.CallActivityWithRetryAsync <ActivityResponse>("GetLeagueSummaryOutputResultsActivity", DomainSettings.QueryRetryOptions(), queryRequest); } catch (FunctionFailedException ffs) { if (null == resp) { resp = new ActivityResponse() { FunctionName = "QueryProjectionProcessorOrchestrator" }; } resp.Message = ffs.Message; resp.FatalError = true; } #region Logging if (null != log) { if (null != resp) { log.LogInformation($"{resp.FunctionName} complete: {resp.Message } "); } } #endregion if (null != resp) { context.SetCustomStatus(resp); if (resp.FatalError) { #region Logging if (null != log) { log.LogError($"Fatal error in {resp.FunctionName} - {resp.Message} "); } #endregion return(null); } } // Get the results for ourselves to return...to do this the query must be complete... Get_League_Summary_Definition_Return ret = await context.CallActivityWithRetryAsync <Get_League_Summary_Definition_Return>("GetLeagueSummaryGetResultsActivity", DomainSettings.QueryRetryOptions(), queryRequest); return(ret); } } } else { if (null != log) { // Unable to get the request details from the orchestration log.LogError("OnGetLeagueSummaryQueryHandlerOrchestrator : Unable to get the query request from the context"); string contextAsString = context.GetInput <string>(); if (!string.IsNullOrWhiteSpace(contextAsString)) { log.LogError($"Context was {contextAsString} "); } else { log.LogError($"Context was blank "); } } return(null); } } catch (Exception ex) { #region Logging if (null != log) { // Error running thew orchestration log.LogError($"OnGetLeagueSummaryQueryHandlerOrchestrator : Error {ex.Message}"); } #endregion if (null != context) { context.SetCustomStatus($"OnGetLeagueSummaryQueryHandlerOrchestrator : Error {ex.Message}"); } throw; } }
public static async Task <HttpResponseMessage> QueryProjectionProcessorRun( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequestMessage req, [OrchestrationClient] DurableOrchestrationClient runProjectionOrchestrationClient, ILogger log) { #region Logging if (null != log) { log.LogInformation("Get all query status by name"); } #endregion int timeoutLength = 30; // seconds int retryWait = 1; // seconds string queryId = req.RequestUri.ParseQueryString()["QueryId"]; string queryName = req.RequestUri.ParseQueryString()["QueryName"]; string notifyOrchestration = req.RequestUri.ParseQueryString()["NotifyOrchestration"]; string asOfDateString = req.RequestUri.ParseQueryString()["AsOfDate"]; DateTime?asOfDate = null; if (!string.IsNullOrWhiteSpace(asOfDateString)) { DateTime dtOut; if (DateTime.TryParse(asOfDateString, out dtOut)) { asOfDate = dtOut; } } string timeoutLengthString = req.RequestUri.ParseQueryString()["TimeOut"]; if (!string.IsNullOrWhiteSpace(timeoutLengthString)) { int.TryParse(timeoutLengthString, out timeoutLength); } string retryWaitString = req.RequestUri.ParseQueryString()["RetryWait"]; if (!string.IsNullOrWhiteSpace(retryWaitString)) { int.TryParse(retryWaitString, out retryWait); } dynamic eventData = await req.Content.ReadAsAsync <object>(); if (null != eventData) { queryId = queryId ?? eventData?.QueryId; queryName = queryName ?? eventData?.QueryName; asOfDate = asOfDate ?? eventData?.AsOfDate; notifyOrchestration = notifyOrchestration ?? eventData?.NotifyOrchestration; } if (!string.IsNullOrWhiteSpace(queryId)) { Query_Projections_Projection_Request payload = new Query_Projections_Projection_Request() { QueryName = queryName, UniqueIdentifier = queryId, AsOfDate = asOfDate, CallbackOrchestrationIdentifier = notifyOrchestration }; // call the orchestrator... string instanceId = await runProjectionOrchestrationClient.StartNewAsync("QueryProjectionProcessorOrchestrator", payload); #region Logging if (null != log) { log.LogInformation($"Started QueryProjectionProcessorOrchestrator - instance id: {instanceId }"); } #endregion // Wait for it to complete TimeSpan timeout = TimeSpan.FromSeconds(timeoutLength); TimeSpan retryInterval = TimeSpan.FromSeconds(retryWait); return(await runProjectionOrchestrationClient.WaitForCompletionOrCreateCheckStatusResponseAsync( req, instanceId, timeout, retryInterval)); } else { return(req.CreateResponse(System.Net.HttpStatusCode.BadRequest, "Please pass a query name and query identifier in the query string or in the request body")); } }
public static async Task <ActivityResponse> QueryProjectionProcessorOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context, Microsoft.Extensions.Logging.ILogger log) { ActivityResponse response = new ActivityResponse() { FunctionName = "QueryProjectionProcessorOrchestrator" }; Query_Projections_Projection_Request request = context.GetInput <Query_Projections_Projection_Request>(); if (null != request) { Guid UniqueIdentifierGuid; if (!Guid.TryParse(request.UniqueIdentifier, out UniqueIdentifierGuid)) { if (!Guid.TryParse(request.CallbackOrchestrationIdentifier, out UniqueIdentifierGuid)) { if (!Guid.TryParse(context.ParentInstanceId, out UniqueIdentifierGuid)) { if (!Guid.TryParse(context.InstanceId, out UniqueIdentifierGuid)) { UniqueIdentifierGuid = Guid.NewGuid(); } } } } // get all the projection requests for the query List <Query_Projections_Projection_Return> allProjections = await context.CallActivityWithRetryAsync <List <Query_Projections_Projection_Return> >("GetQueryProjectionsStatusProjectionActivity", DomainSettings.QueryRetryOptions(), request); if (null != allProjections) { #region Logging if (null != log) { log.LogInformation($"Query {request.QueryName}.{request.UniqueIdentifier} has {allProjections.Count} projections total "); } #endregion // Run them - This should be done by fan-out/fan-in List <Task <ProjectionResultsRecord <object> > > allProjectionTasks = new List <Task <ProjectionResultsRecord <object> > >(); // run all the outstanding projections in parallel foreach (Query_Projections_Projection_Return projectionRequest in allProjections) { if (projectionRequest.ProjectionState == Query_Projections_Projection_Return.QueryProjectionState.Queued) { ProjectionRequest projRequest = new ProjectionRequest() { ParentRequestName = request.QueryName, CorrelationIdentifier = UniqueIdentifierGuid, DomainName = projectionRequest.Projection.DomainName, AggregateTypeName = projectionRequest.Projection.AggregateTypeName, AggregateInstanceUniqueIdentifier = projectionRequest.Projection.InstanceKey, AsOfDate = request.AsOfDate, ProjectionName = projectionRequest.Projection.ProjectionTypeName }; if (null != projRequest) { context.SetCustomStatus(projRequest); } // mark it as in-flight response = await context.CallActivityWithRetryAsync <ActivityResponse>("LogQueryProjectionInFlightActivity", DomainSettings.QueryRetryOptions(), projRequest); if (null != response) { context.SetCustomStatus(response); } } } // Now start them running using a fan-out/fan in pattern foreach (Query_Projections_Projection_Return projectionRequest in allProjections) { if (projectionRequest.ProjectionState == Query_Projections_Projection_Return.QueryProjectionState.Queued) { ProjectionRequest projRequest = new ProjectionRequest() { ParentRequestName = request.QueryName, CorrelationIdentifier = UniqueIdentifierGuid, DomainName = projectionRequest.Projection.DomainName, AggregateTypeName = projectionRequest.Projection.AggregateTypeName, AggregateInstanceUniqueIdentifier = projectionRequest.Projection.InstanceKey, AsOfDate = request.AsOfDate, ProjectionName = projectionRequest.Projection.ProjectionTypeName }; // and start running it... allProjectionTasks.Add(context.CallActivityWithRetryAsync <ProjectionResultsRecord <object> >("RunProjectionActivity", DomainSettings.QueryRetryOptions(), projRequest)); } } // Run the projections in parallel... await Task.WhenAll(allProjectionTasks); // and save their results to the query foreach (var returnValue in allProjectionTasks) { ProjectionResultsRecord <object> result = returnValue.Result; if (null != result) { if (!result.Error) { response = await context.CallActivityWithRetryAsync <ActivityResponse>("LogQueryProjectionResultActivity", DomainSettings.QueryRetryOptions(), result); } else { #region Logging if (null != log) { log.LogError($"Error running projection {result.ProjectionName} - {result.StatusMessage} "); } #endregion response.Message = $"Error running projection {result.ProjectionName} - {result.StatusMessage} "; } if (null != response) { context.SetCustomStatus(response); } } else { #region Logging if (null != log) { log.LogError($"Projection {returnValue.Id} did not return any values : {returnValue.Exception}"); } #endregion } } } // when all done - trigger the calling orchestration to come out of hibernation if (!string.IsNullOrWhiteSpace(request.CallbackOrchestrationIdentifier)) { } } else { response.Message = $"Unable to read projection request data from context {context.InstanceId}"; response.FatalError = true; } return(response); }
public static async Task <ActivityResponse> GetLeagueSummaryQueryProjectionProcessOrchestrator ([OrchestrationTrigger] DurableOrchestrationContext context, Microsoft.Extensions.Logging.ILogger log) { ActivityResponse resp = new ActivityResponse() { FunctionName = "GetLeagueSummaryQueryProjectionProcessOrchestrator" }; // Get the query definition form the context... QueryRequest <Get_League_Summary_Definition> queryRequest = context.GetInput <QueryRequest <Get_League_Summary_Definition> >(); if (null != queryRequest) { // Get all the outstanding projection requests Query_Projections_Projection_Request projectionQueryRequest = new Query_Projections_Projection_Request() { UniqueIdentifier = queryRequest.QueryUniqueIdentifier.ToString(), QueryName = queryRequest.QueryName }; List <Query_Projections_Projection_Return> allProjections = await context.CallActivityAsync <List <Query_Projections_Projection_Return> >("GetQueryProjectionsStatusProjectionActivity", projectionQueryRequest); if (null != allProjections) { // This should be done by fan-out/fan-in List <Task <ProjectionResultsRecord <Get_League_Summary_Definition_Return> > > allProjectionTasks = new List <Task <ProjectionResultsRecord <Get_League_Summary_Definition_Return> > >(); // run all the outstanding projections in parallel foreach (Query_Projections_Projection_Return projectionRequest in allProjections) { if (projectionRequest.ProjectionState == Query_Projections_Projection_Return.QueryProjectionState.Queued) { ProjectionRequest projRequest = new ProjectionRequest() { ParentRequestName = queryRequest.QueryName, CorrelationIdentifier = queryRequest.QueryUniqueIdentifier, DomainName = "Leagues", AggregateTypeName = "League", AggregateInstanceUniqueIdentifier = projectionRequest.Projection.InstanceKey, AsOfDate = null, ProjectionName = projectionRequest.Projection.ProjectionTypeName }; // mark it as in-flight resp = await context.CallActivityAsync <ActivityResponse>("LogQueryProjectionInFlightActivity", projRequest); if (null != resp) { context.SetCustomStatus(resp); } // and start running it... allProjectionTasks.Add(context.CallActivityAsync <ProjectionResultsRecord <Get_League_Summary_Definition_Return> >("RunLeagueSummaryInformationProjectionActivity", projRequest)); } } #region Logging if (null != log) { log.LogInformation($"Running {allProjectionTasks.Count } projections in parallel"); } #endregion // and persist their results to the query context.SetCustomStatus($"Running {allProjectionTasks.Count } projections in parallel"); await Task.WhenAll(allProjectionTasks); #region Logging if (null != log) { log.LogInformation($"Completed running {allProjectionTasks.Count } projections in parallel"); } #endregion foreach (var returnValue in allProjectionTasks) { ProjectionResultsRecord <Get_League_Summary_Definition_Return> projectionResponse = returnValue.Result; // add in the extra details projectionResponse.CorrelationIdentifier = queryRequest.QueryUniqueIdentifier; projectionResponse.ParentRequestName = queryRequest.QueryName; // log the result... resp = await context.CallActivityAsync <ActivityResponse>("LogQueryProjectionResultActivity", projectionResponse); #region Logging if (null != log) { if (null != resp) { log.LogInformation($"{resp.FunctionName} complete: {resp.Message } "); } } #endregion if (null != resp) { context.SetCustomStatus(resp); } } } } return(resp); }