public async Task <string> ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor, object environment, CancellationToken cancellationToken) { await _recipeEventHandlers.InvokeAsync((handler, executionId, recipeDescriptor) => handler.RecipeExecutingAsync(executionId, recipeDescriptor), executionId, recipeDescriptor, _logger); try { _environmentMethodProvider = new ParametersMethodProvider(environment); _configurationMethodProvider = new ConfigurationMethodProvider(_shellSettings.ShellConfiguration); var result = new RecipeResult { ExecutionId = executionId }; using (var stream = recipeDescriptor.RecipeFileInfo.CreateReadStream()) { using (var file = new StreamReader(stream)) { using (var reader = new JsonTextReader(file)) { // Go to Steps, then iterate. while (await reader.ReadAsync()) { if (reader.Path == "variables") { await reader.ReadAsync(); var variables = await JObject.LoadAsync(reader); _variablesMethodProvider = new VariablesMethodProvider(variables); } if (reader.Path == "steps" && reader.TokenType == JsonToken.StartArray) { while (await reader.ReadAsync() && reader.Depth > 1) { if (reader.Depth == 2) { var child = await JObject.LoadAsync(reader); var recipeStep = new RecipeExecutionContext { Name = child.Value <string>("name"), Step = child, ExecutionId = executionId, Environment = environment, RecipeDescriptor = recipeDescriptor }; if (cancellationToken.IsCancellationRequested) { _logger.LogError("Recipe interrupted by cancellation token."); return(null); } var stepResult = new RecipeStepResult { StepName = recipeStep.Name }; result.Steps.Add(stepResult); ExceptionDispatchInfo capturedException = null; try { await ExecuteStepAsync(recipeStep); stepResult.IsSuccessful = true; } catch (Exception e) { stepResult.IsSuccessful = false; stepResult.ErrorMessage = e.ToString(); // Because we can't do some async processing the in catch or finally // blocks, we store the exception to throw it later. capturedException = ExceptionDispatchInfo.Capture(e); } stepResult.IsCompleted = true; if (stepResult.IsSuccessful == false) { capturedException.Throw(); } if (recipeStep.InnerRecipes != null) { foreach (var descriptor in recipeStep.InnerRecipes) { var innerExecutionId = Guid.NewGuid().ToString(); await ExecuteAsync(innerExecutionId, descriptor, environment, cancellationToken); } } } } } } } } } await _recipeEventHandlers.InvokeAsync((handler, executionId, recipeDescriptor) => handler.RecipeExecutedAsync(executionId, recipeDescriptor), executionId, recipeDescriptor, _logger); return(executionId); } catch (Exception) { await _recipeEventHandlers.InvokeAsync((handler, executionId, recipeDescriptor) => handler.ExecutionFailedAsync(executionId, recipeDescriptor), executionId, recipeDescriptor, _logger); throw; } }
public async Task <string> ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor, object environment) { await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.RecipeExecutingAsync(executionId, recipeDescriptor)); try { _environmentMethodProvider = new ParametersMethodProvider(environment); var result = new RecipeResult { ExecutionId = executionId }; await _recipeStore.CreateAsync(result); using (StreamReader file = File.OpenText(recipeDescriptor.RecipeFileInfo.PhysicalPath)) { using (var reader = new JsonTextReader(file)) { // Go to Steps, then iterate. while (reader.Read()) { if (reader.Path == "variables") { reader.Read(); var variables = JObject.Load(reader); _variablesMethodProvider = new VariablesMethodProvider(variables); } if (reader.Path == "steps" && reader.TokenType == JsonToken.StartArray) { while (reader.Read() && reader.Depth > 1) { if (reader.Depth == 2) { var child = JObject.Load(reader); var recipeStep = new RecipeExecutionContext { Name = child.Value <string>("name"), Step = child, ExecutionId = executionId, Environment = environment }; var stepResult = new RecipeStepResult { StepName = recipeStep.Name }; result.Steps.Add(stepResult); await _recipeStore.UpdateAsync(result); ExceptionDispatchInfo capturedException = null; try { await ExecuteStepAsync(recipeStep); stepResult.IsSuccessful = true; } catch (Exception e) { stepResult.IsSuccessful = false; stepResult.ErrorMessage = e.ToString(); // Because we can't do some async processing the in catch or finally // blocks, we store the exception to throw it later. capturedException = ExceptionDispatchInfo.Capture(e); } stepResult.IsCompleted = true; await _recipeStore.UpdateAsync(result); if (stepResult.IsSuccessful == false) { capturedException.Throw(); } } } } } } } await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.RecipeExecutedAsync(executionId, recipeDescriptor)); return(executionId); } catch (Exception) { await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.ExecutionFailedAsync(executionId, recipeDescriptor)); throw; } }
public async Task <string> ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor) { await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.RecipeExecutingAsync(executionId, recipeDescriptor)); try { RecipeResult result = new RecipeResult { ExecutionId = executionId }; List <RecipeStepResult> stepResults = new List <RecipeStepResult>(); using (StreamReader file = File.OpenText(recipeDescriptor.RecipeFileInfo.PhysicalPath)) { using (var reader = new JsonTextReader(file)) { VariablesMethodProvider variablesMethodProvider = null; // Go to Steps, then iterate. while (reader.Read()) { if (reader.Path == "variables") { reader.Read(); var variables = JObject.Load(reader); variablesMethodProvider = new VariablesMethodProvider(variables); } if (reader.Path == "steps" && reader.TokenType == JsonToken.StartArray) { int stepId = 0; while (reader.Read() && reader.Depth > 1) { if (reader.Depth == 2) { var child = JToken.Load(reader); var recipeStep = new RecipeStepDescriptor { Id = (stepId++).ToString(), Name = child.Value <string>("name"), Step = child }; var shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings); using (var scope = shellContext.CreateServiceScope()) { if (!shellContext.IsActivated) { var eventBus = scope.ServiceProvider.GetService <IEventBus>(); await eventBus.NotifyAsync <IOrchardShellEvents>(x => x.ActivatingAsync()); await eventBus.NotifyAsync <IOrchardShellEvents>(x => x.ActivatedAsync()); shellContext.IsActivated = true; } var recipeStepExecutor = scope.ServiceProvider.GetRequiredService <IRecipeStepExecutor>(); var scriptingManager = scope.ServiceProvider.GetRequiredService <IScriptingManager>(); if (variablesMethodProvider != null) { variablesMethodProvider.ScriptingManager = scriptingManager; scriptingManager.GlobalMethodProviders.Add(variablesMethodProvider); } if (_applicationLifetime.ApplicationStopping.IsCancellationRequested) { throw new OrchardException(T["Recipe cancelled, application is restarting"]); } EvaluateJsonTree(scriptingManager, recipeStep.Step); await recipeStepExecutor.ExecuteAsync(executionId, recipeStep); } // The recipe execution might have invalidated the shell by enabling new features, // so the deferred tasks need to run on an updated shell context if necessary. shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings); using (var scope = shellContext.CreateServiceScope()) { var recipeStepExecutor = scope.ServiceProvider.GetRequiredService <IRecipeStepExecutor>(); var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>(); // The recipe might have added some deferred tasks to process if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks) { var taskContext = new DeferredTaskContext(scope.ServiceProvider); await deferredTaskEngine.ExecuteTasksAsync(taskContext); } } } } } } } } await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.RecipeExecutedAsync(executionId, recipeDescriptor)); return(executionId); } catch (Exception) { await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.ExecutionFailedAsync(executionId, recipeDescriptor)); throw; } }