public async Task <Core.Models.ExecutionContext> ProcessRequestAsync(ExecutionRequest execRequest, CancellationToken cancelToken) { if (execRequest == null) { throw new ArgumentNullException(nameof(execRequest)); } // We're about to execute the extension. Update the execution status to [Processing]. var execContext = execRequest.ToExecutionContext().UpdateStatus(ExecutionStatus.Processing); logger.LogInformation($"Updating execution [{execRequest.ExecutionId}] status: [{execContext.Status}]..."); await UpdateExecutionStatusAsync(execRequest.UpdateExecutionStatusUrl, execContext.ToExecutionUpdate()); logger.LogInformation($"Processing execution request [{execRequest.ExecutionId}]..."); // Invoke the execution adapter and execute the extension. execContext = await this.execAdapter.ExecuteAsync(execRequest, cancelToken); logger.LogInformation($"Updating execution [{execRequest.ExecutionId}] status: [{execContext.Status}]..."); // All done! Update the execution status based on the response from the execution adapter. await UpdateExecutionStatusAsync(execRequest.UpdateExecutionStatusUrl, execContext.ToExecutionUpdate()); return(execContext); }
public void ToExecutionContext_GivenExecutionRequest_ShouldReturnEquivalentExecutionContext() { var execRequest = new ExecutionRequest { CreatedDateTimeUtc = DateTime.UtcNow.AddMinutes(-10), ExecutionProfileName = "DefaultExecutionProfile", ExecutionId = Guid.NewGuid().ToString(), ExtensionId = Guid.NewGuid().ToString(), ExtensionVersionId = Guid.NewGuid().ToString(), LastUpdatedDateTimeUtc = DateTime.UtcNow.AddMinutes(-5), Priority = ExecutionPriority.High, StatusUpdateKey = Guid.NewGuid().ToString(), ExecutionTimeoutDateTimeUtc = DateTime.UtcNow.AddHours(1), ExecutionModelName = "DefaultExecutionModel", ObjectProviderName = "DefaultObjectProvider", SupportedServices = new Dictionary <string, JObject> { ["ServiceA"] = null }, ProvidedInputObjects = new List <string> { "InputObjectA" }, InputObjects = new Dictionary <string, ExtensionInputObject> { ["InputObjectA"] = null }, OutputObjects = new Dictionary <string, ExtensionOutputObject> { ["OutputObjectA"] = null } }; var execContext = execRequest.ToExecutionContext(); execContext.Should().NotBeNull(); execContext.CreatedDateTimeUtc.Should().Be(execRequest.CreatedDateTimeUtc); execContext.ExecutionProfileName.Should().Be(execRequest.ExecutionProfileName); execContext.ExecutionId.Should().Be(execRequest.ExecutionId); execContext.ExtensionId.Should().Be(execRequest.ExtensionId); execContext.ExtensionVersionId.Should().Be(execRequest.ExtensionVersionId); execContext.LastUpdatedDateTimeUtc.Should().Be(execRequest.LastUpdatedDateTimeUtc); execContext.Priority.Should().Be(execRequest.Priority); execContext.StatusUpdateKey.Should().Be(execRequest.StatusUpdateKey); execContext.ExecutionTimeoutDateTimeUtc.Should().Be(execRequest.ExecutionTimeoutDateTimeUtc); execContext.ExecutionModelName.Should().Be(execRequest.ExecutionModelName); execContext.ObjectProviderName.Should().Be(execRequest.ObjectProviderName); execContext.SupportedServices.Should().BeEquivalentTo(execRequest.SupportedServices); execContext.ProvidedInputObjects.Should().BeEquivalentTo(execRequest.ProvidedInputObjects); execContext.InputObjects.Should().BeEquivalentTo(execRequest.InputObjects); execContext.OutputObjects.Should().BeEquivalentTo(execRequest.OutputObjects); }
public Task <Draco.Core.Models.ExecutionContext> ExecuteAsync(ExecutionRequest request, CancellationToken cancelToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (cancelToken == null) { throw new ArgumentNullException(nameof(cancelToken)); } // We're not actually doing anything. Mark the execution as [Succeeded] and move on... return(Task.FromResult(request.ToExecutionContext().UpdateStatus(ExecutionStatus.Succeeded))); }
public async Task <Core.Models.ExecutionContext> ExecuteAsync(ExecutionRequest request, CancellationToken cancelToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var requestJson = JsonConvert.SerializeObject(request); var requestMessage = new Message(Encoding.UTF8.GetBytes(requestJson)); requestMessage.UserProperties.Add(nameof(ExecutionRequest.ExecutionModelName), request.ExecutionModelName); requestMessage.UserProperties.Add(nameof(ExecutionRequest.ExecutionProfileName), request.ExecutionProfileName); requestMessage.UserProperties.Add(nameof(ExecutionRequest.Priority), request.Priority.ToString()); await topicClient.SendAsync(requestMessage); return(request.ToExecutionContext().UpdateStatus(ExecutionStatus.Queued)); }
public async Task <Core.Models.ExecutionContext> ExecuteAsync(ExecutionRequest execRequest, CancellationToken cancelToken) { if (execRequest == null) { throw new ArgumentNullException(nameof(execRequest)); } logger.LogInformation($"Processing execution request [{execRequest.ExecutionId}]..."); // Give all the applicable extension services a chance to do any synchronous pre-work ahead of the actual execution... // For more information on extension services, see /doc/architecture/extension-services.md. await(execRequest.ValidateOnly ? this.execServiceProvider.OnValidatingAsync(execRequest) : this.execServiceProvider.OnExecutingAsync(execRequest)); // UTC now + the execution timeout on the execution request if it was provided. // If no execution timeout was defined, default to an hour [defaultTimeoutPeriod]. execRequest.CalculateExecutionTimeoutDateTimeUtc(defaultTimeoutPeriod); logger.LogDebug($"Execution [{execRequest.ExecutionId}] timeout set to [{execRequest.ExecutionTimeoutDateTimeUtc}] UTC."); // We're about to execution the extension. Create an execution context to capture the results... var execContext = execRequest.ToExecutionContext(); try { // Deserialize the execution model-specific settings, provided in the [execRequest.extensionSettings] JSON object property, // to get the execution and/or validation URLs that we need to handle the request. var httpSettings = GetHttpExtensionSettings(execRequest); // Create the execution request that we'll POST to the extension... var httpExecRequest = await ToHttpExecutionRequestAsync(execRequest); logger.LogDebug($"Execution [{execRequest.ExecutionId}] URL is [{httpSettings.ExecutionUrl}]."); logger.LogDebug(string.IsNullOrEmpty(httpSettings.ValidationUrl) ? $"Execution [{execRequest.ExecutionId}] validation URL is [{httpSettings.ValidationUrl}]." : $"Execution [{execRequest.ExecutionId}] validation URL not provided."); // If there was a valid RSA public/private key pair provided along with the request, // sign the request before we send it along to the extension... if (!string.IsNullOrEmpty(execRequest.SignatureRsaKeyXml)) { logger.LogDebug($"Signing execution request [{execRequest.ExecutionId}]..."); httpExecRequest.Signature = await httpExecRequestSigner.GenerateSignatureAsync(execRequest.SignatureRsaKeyXml, httpExecRequest); } if (execRequest.ValidateOnly) { // If it's a validation only request, make sure that the extension actually supports validation. // Under normal circumstances, this should have been caught way further upstream at the execution API. if (execRequest.IsValidationSupported == false) { throw new NotSupportedException($"Extension [{execRequest.ExtensionId}:{execRequest.ExtensionVersionId}] " + "does not support validation."); } // Validate the request... execContext = await ValidateAsync(execContext, httpExecRequest, httpSettings); } else { // Execute the request... execContext = await ExecuteAsync(execContext, httpExecRequest, httpSettings); } } catch (Exception ex) { logger.LogError($"An error occurred while processing execution request [{execRequest.ExecutionId}]: [{ex.Message}]."); execContext.UpdateStatus(ExecutionStatus.Failed); } finally { // Give all the applicable extension services a chance to do any synchronous post-work after the execution // regardless of whether or not it succeeded. For more information on extension services, see /doc/architecture/extension-services.md. await(execRequest.ValidateOnly ? this.execServiceProvider.OnValidatedAsync(execContext) : this.execServiceProvider.OnExecutedAsync(execContext)); logger.LogInformation($"Execution request [{execRequest.ExecutionId}] processing complete."); } return(execContext); }