/// <summary> /// Run a workflow step /// </summary> /// <param name="workflowMessage">Message to pass to the step class</param> /// <param name="retryStepTimes">Times to retry on error</param> /// <param name="workflowStep">The step to run</param> internal void RunFrameworkStep(IWorkflowMessage workflowMessage, int retryStepTimes, ProcessorStep workflowStep, ProcessorJob currentJob, bool isCheckDepends) { bool impersonated = false; if (!string.IsNullOrEmpty(workflowStep.RunAsDomain) && !string.IsNullOrEmpty(workflowStep.RunAsUser) && !string.IsNullOrEmpty(workflowStep.RunAsPassword) && workflowStep.RunMode == FrameworkStepRunMode.STA) impersonated = impersonate.ImpersonateValidUser(workflowStep.RunAsUser, workflowStep.RunAsDomain, workflowStep.RunAsPassword); using (IStep step = StepFactory.GetStep(workflowStep.InvokeClass)) { try { workflowStep.RunStatus = FrameworkStepRunStatus.Loaded; if (isCheckDepends) WaitForDependents(workflowStep, currentJob); workflowStep.StartDate = DateTime.Now; step.RunStep(workflowMessage); workflowStep.EndDate = DateTime.Now; workflowStep.RunStatus = FrameworkStepRunStatus.Complete; workflowStep.ExitMessage = "Complete"; } catch (Exception e) { workflowStep.RunStatus = FrameworkStepRunStatus.CompleteWithErrors; workflowStep.ExitMessage = e.Message; while (e.InnerException != null) { e = e.InnerException; workflowStep.ExitMessage += '|' + e.Message; } switch (workflowStep.OnError) { case OnFrameworkStepError.RetryStep: if (workflowStep.WaitBetweenRetriesMilliseconds > 0) Thread.Sleep(workflowStep.WaitBetweenRetriesMilliseconds); // Try the step again retryStepTimes++; if (retryStepTimes <= workflowStep.RetryTimes) RunFrameworkStep(workflowMessage, retryStepTimes, workflowStep, currentJob, isCheckDepends); break; default: // If this is running from a thread, do not throw the error up if (workflowStep.RunMode == FrameworkStepRunMode.STA) throw e; else Processor.ReportJobError(e, workflowStep, workflowMessage, currentJob); break; } } } if (impersonated) impersonate.UndoImpersonation(); }
/// <summary> /// Load the Job's steps /// </summary> /// <param name="processorJob">The ProcessorJob to load to</param> /// <param name="queuesNode">The XmlNode to load from</param> private static void LoadJobSteps(ProcessorJob processorJob, XmlNode stepsNode) { foreach (XmlNode stepNode in stepsNode.ChildNodes) { ProcessorStep workFlowStep = new ProcessorStep(); if (!string.IsNullOrEmpty(stepNode.Attributes["Name"].Value)) //Required workFlowStep.StepName = stepNode.Attributes["Name"].Value; if (!string.IsNullOrEmpty(stepNode.Attributes["Group"].Value)) //Required workFlowStep.Group = stepNode.Attributes["Group"].Value; if (!string.IsNullOrEmpty(stepNode.Attributes["InvokeClass"].Value)) //Required workFlowStep.InvokeClass = stepNode.Attributes["InvokeClass"].Value; if (stepNode.Attributes["OnError"] != null && !string.IsNullOrEmpty(stepNode.Attributes["OnError"].Value)) workFlowStep.OnError = (OnFrameworkStepError)Enum.Parse(typeof(OnFrameworkStepError), stepNode.Attributes["OnError"].Value, true); if (stepNode.Attributes["RetryTimes"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RetryTimes"].Value)) { int retryTimes = 0; int.TryParse(stepNode.Attributes["RetryTimes"].Value, out retryTimes); workFlowStep.RetryTimes = retryTimes; } if (stepNode.Attributes["WaitBetweenRetriesMilliseconds"] != null && !string.IsNullOrEmpty(stepNode.Attributes["WaitBetweenRetriesMilliseconds"].Value)) { int waitBetweenRetriesMilliseconds = 0; int.TryParse(stepNode.Attributes["WaitBetweenRetriesMilliseconds"].Value, out waitBetweenRetriesMilliseconds); workFlowStep.WaitBetweenRetriesMilliseconds = waitBetweenRetriesMilliseconds; } if (stepNode.Attributes["RunMode"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunMode"].Value)) workFlowStep.RunMode = (FrameworkStepRunMode)Enum.Parse(typeof(FrameworkStepRunMode), stepNode.Attributes["RunMode"].Value, true); if (stepNode.Attributes["DependsOn"] != null && !string.IsNullOrEmpty(stepNode.Attributes["DependsOn"].Value)) workFlowStep.DependsOn = stepNode.Attributes["DependsOn"].Value; if (stepNode.Attributes["DependsOnGroup"] != null && !string.IsNullOrEmpty(stepNode.Attributes["DependsOnGroup"].Value)) workFlowStep.DependsOnGroup = stepNode.Attributes["DependsOnGroup"].Value; if (stepNode.Attributes["WaitForDependsOnMilliseconds"] != null && !string.IsNullOrEmpty(stepNode.Attributes["WaitForDependsOnMilliseconds"].Value)) { int waitForDependsOnMilliseconds = int.MaxValue; if (!string.IsNullOrEmpty(stepNode.Attributes["WaitForDependsOnMilliseconds"].Value)) int.TryParse(stepNode.Attributes["WaitForDependsOnMilliseconds"].Value, out waitForDependsOnMilliseconds); workFlowStep.WaitForDependsOnMilliseconds = waitForDependsOnMilliseconds; } if (stepNode.Attributes["RunAsDomain"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunAsDomain"].Value)) workFlowStep.RunAsDomain = Utils.GetDecryptedString(stepNode.Attributes["RunAsDomain"].Value); if (stepNode.Attributes["RunAsUser"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunAsUser"].Value)) workFlowStep.RunAsUser = Utils.GetDecryptedString(stepNode.Attributes["RunAsUser"].Value); if (stepNode.Attributes["RunAsPassword"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunAsPassword"].Value)) workFlowStep.RunAsPassword = Utils.GetDecryptedString(stepNode.Attributes["RunAsPassword"].Value); processorJob.WorkFlowSteps.Add(workFlowStep); } }
/// <summary> /// Block untill all steps and groups this step depends on have finished /// </summary> /// <param name="workflowStep"></param> private void WaitForDependents(ProcessorStep workflowStep, ProcessorJob currentJob) { if (string.IsNullOrEmpty(workflowStep.DependsOn) && string.IsNullOrEmpty(workflowStep.DependsOnGroup)) return; var result = from ProcessorStep in currentJob.WorkFlowSteps where ProcessorStep.RunStatus != FrameworkStepRunStatus.Complete && (workflowStep.DependsOn.Split(',').Contains(ProcessorStep.StepName) || workflowStep.DependsOnGroup.Split(',').Contains(ProcessorStep.Group)) select ProcessorStep; if (result.Count() > 0) //There are still steps to wait for { Thread.Sleep(100); workflowStep.RunStatusTime += 100; if (workflowStep.RunStatusTime <= workflowStep.WaitForDependsOnMilliseconds) WaitForDependents(workflowStep, currentJob); } }
/// <summary> /// Reports a job error /// </summary> /// <param name="e">The exception to report</param> /// <param name="step">The step the exception accrued</param> /// <param name="workflowMessage">The original message pulled from the queue</param> public static void ReportJobError(Exception e, ProcessorStep workflowStep, IWorkflowMessage workflowMessage, ProcessorJob currentJob) { // Push an error message to the error Queue WorkflowErrorMessage errorMessage = new WorkflowErrorMessage() { ExceptionMessage = e.Message, JobName = currentJob.JobName, StepName = workflowStep.StepName }; //if e contains inner exceptions, add those messages while (e.InnerException != null) { //assign e to the inner exception - recursive e = e.InnerException; errorMessage.ExceptionMessage += '|' + e.Message; } FrameworkManager.AddFrameworkError(currentJob, workflowMessage, errorMessage); }