internal void StartChain(string flowName, StepExecutionContext context) { var definitions = from definition in _Definitions where definition.FlowCode.Equals(flowName, StringComparison.InvariantCultureIgnoreCase) select definition; foreach (var definition in definitions) { definition.Steps.ForEach((step) => ProceedStep(step, context)); } }
private void ProceedStep(MachineWorkStep step, StepExecutionContext context) { IInvocation invocation = context.Invocation; step.Context = context; if (step.RequiresAttributeType == null) { step.ExecuteStep(invocation, null); _logger.DebugFormat("'{0}' has executed. No Aspect is required.", step.StepName); return; } IEnumerable<object> attribute = AttributesHelper.GetAttributes(invocation, step.RequiresAttributeType); if (attribute == null || attribute.Count() == 0) { _logger.DebugFormat("'{0}' can not be executed. No aspect was applied.", step.StepName); return; } step.ExecuteStep(invocation, attribute.Cast<AspectAttributeBase>()); _logger.DebugFormat("'{0}' has executed. Aspects are applied.", step.StepName); }
public async Task <WorkflowExecutorResult> Execute(WorkflowInstance workflow, WorkflowOptions options) { var wfResult = new WorkflowExecutorResult(); var exePointers = new List <ExecutionPointer>(workflow.ExecutionPointers.Where(x => x.Active && (!x.SleepUntil.HasValue || x.SleepUntil < _datetimeProvider.Now.ToUniversalTime()))); var def = _registry.GetDefinition(workflow.WorkflowDefinitionId, workflow.Version); if (def == null) { _logger.LogError("Workflow {0} version {1} is not registered", workflow.WorkflowDefinitionId, workflow.Version); return(wfResult); } foreach (var pointer in exePointers) { var step = def.Steps.First(x => x.Id == pointer.StepId); if (step != null) { try { switch (step.InitForExecution(wfResult, def, workflow, pointer)) { case ExecutionPipelineDirective.Defer: continue; case ExecutionPipelineDirective.EndWorkflow: workflow.Status = WorkflowStatus.Complete; workflow.CompleteTime = _datetimeProvider.Now.ToUniversalTime(); continue; } if (!pointer.StartTime.HasValue) { pointer.StartTime = _datetimeProvider.Now.ToUniversalTime(); } _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id); IStepBody body = step.ConstructBody(_serviceProvider); if (body == null) { _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString()); pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(options.ErrorRetryInterval); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = String.Format("Unable to construct step body {0}", step.BodyType.ToString()) }); continue; } IStepExecutionContext context = new StepExecutionContext() { Workflow = workflow, Step = step, PersistenceData = pointer.PersistenceData, ExecutionPointer = pointer, Item = pointer.ContextItem }; ProcessInputs(workflow, step, body, context); switch (step.BeforeExecute(wfResult, context, pointer, body)) { case ExecutionPipelineDirective.Defer: continue; case ExecutionPipelineDirective.EndWorkflow: workflow.Status = WorkflowStatus.Complete; workflow.CompleteTime = _datetimeProvider.Now.ToUniversalTime(); continue; } var result = await body.RunAsync(context); if (result.Proceed) { ProcessOutputs(workflow, step, body); } ProcessExecutionResult(workflow, def, pointer, step, result, wfResult); step.AfterExecute(wfResult, context, result, pointer); } catch (Exception ex) { pointer.RetryCount++; _logger.LogError("Workflow {0} raised error on step {1} Message: {2}", workflow.Id, pointer.StepId, ex.Message); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = ex.Message }); switch (step.ErrorBehavior ?? def.DefaultErrorBehavior) { case WorkflowErrorHandling.Retry: pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(step.RetryInterval ?? def.DefaultErrorRetryInterval ?? options.ErrorRetryInterval); break; case WorkflowErrorHandling.Suspend: workflow.Status = WorkflowStatus.Suspended; break; case WorkflowErrorHandling.Terminate: workflow.Status = WorkflowStatus.Terminated; break; } Host.ReportStepError(workflow, step, ex); } } else { _logger.LogError("Unable to find step {0} in workflow definition", pointer.StepId); pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(options.ErrorRetryInterval); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = String.Format("Unable to find step {0} in workflow definition", pointer.StepId) }); } } ProcessAfterExecutionIteration(workflow, def, wfResult); DetermineNextExecutionTime(workflow); return(wfResult); }
private async Task ExecuteStep(WorkflowInstance workflow, WorkflowStep step, ExecutionPointer pointer, WorkflowExecutorResult wfResult, WorkflowDefinition def) { using (var scope = _scopeProvider.CreateScope()) { _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id); IStepBody body = step.ConstructBody(scope.ServiceProvider); if (body == null) { _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString()); pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(_options.ErrorRetryInterval); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = $"Unable to construct step body {step.BodyType.ToString()}" }); return; } IStepExecutionContext context = new StepExecutionContext() { Workflow = workflow, Step = step, PersistenceData = pointer.PersistenceData, ExecutionPointer = pointer, Item = pointer.ContextItem }; foreach (var input in step.Inputs) { input.AssignInput(workflow.Data, body, context); } switch (step.BeforeExecute(wfResult, context, pointer, body)) { case ExecutionPipelineDirective.Defer: return; case ExecutionPipelineDirective.EndWorkflow: workflow.Status = WorkflowStatus.Complete; workflow.CompleteTime = _datetimeProvider.Now.ToUniversalTime(); return; } var result = await body.RunAsync(context); if (result.Proceed) { foreach (var output in step.Outputs) { output.AssignOutput(workflow.Data, body, context); } } _executionResultProcessor.ProcessExecutionResult(workflow, def, pointer, step, result, wfResult); step.AfterExecute(wfResult, context, result, pointer); } }
public async Task <WorkflowExecutorResult> Execute(WorkflowInstance workflow) { var wfResult = new WorkflowExecutorResult(); var exePointers = new List <ExecutionPointer>(workflow.ExecutionPointers.Where(x => x.Active && (!x.SleepUntil.HasValue || x.SleepUntil < _datetimeProvider.Now.ToUniversalTime()))); var def = _registry.GetDefinition(workflow.WorkflowDefinitionId, workflow.Version); if (def == null) { _logger.LogError("Workflow {0} version {1} is not registered", workflow.WorkflowDefinitionId, workflow.Version); return(wfResult); } foreach (var pointer in exePointers) { if (pointer.Status == PointerStatus.Cancelled) { continue; } var step = def.Steps.FindById(pointer.StepId); if (step == null) { _logger.LogError("Unable to find step {0} in workflow definition", pointer.StepId); pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(_options.ErrorRetryInterval); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = String.Format("Unable to find step {0} in workflow definition", pointer.StepId) }); continue; } try { switch (step.InitForExecution(wfResult, def, workflow, pointer)) { case ExecutionPipelineDirective.Defer: continue; case ExecutionPipelineDirective.EndWorkflow: workflow.Status = WorkflowStatus.Complete; workflow.CompleteTime = _datetimeProvider.Now.ToUniversalTime(); continue; } if (pointer.Status != PointerStatus.Running) { pointer.Status = PointerStatus.Running; _publisher.PublishNotification(new StepStarted() { EventTimeUtc = _datetimeProvider.Now, Reference = workflow.Reference, ExecutionPointerId = pointer.Id, StepId = step.Id, WorkflowInstanceId = workflow.Id, WorkflowDefinitionId = workflow.WorkflowDefinitionId, Version = workflow.Version }); } if (!pointer.StartTime.HasValue) { pointer.StartTime = _datetimeProvider.Now.ToUniversalTime(); } using (var scope = _scopeProvider.CreateScope()) { _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id); IStepBody body = step.ConstructBody(scope.ServiceProvider); if (body == null) { _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString()); pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(_options.ErrorRetryInterval); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = String.Format("Unable to construct step body {0}", step.BodyType.ToString()) }); continue; } IStepExecutionContext context = new StepExecutionContext() { Workflow = workflow, Step = step, PersistenceData = pointer.PersistenceData, ExecutionPointer = pointer, Item = pointer.ContextItem }; foreach (var input in step.Inputs) { input.AssignInput(workflow.Data, body, context); } switch (step.BeforeExecute(wfResult, context, pointer, body)) { case ExecutionPipelineDirective.Defer: continue; case ExecutionPipelineDirective.EndWorkflow: workflow.Status = WorkflowStatus.Complete; workflow.CompleteTime = _datetimeProvider.Now.ToUniversalTime(); continue; } var result = await body.RunAsync(context); if (result.Proceed) { foreach (var output in step.Outputs) { output.AssignOutput(workflow.Data, body, context); } } _executionResultProcessor.ProcessExecutionResult(workflow, def, pointer, step, result, wfResult); step.AfterExecute(wfResult, context, result, pointer); } } catch (Exception ex) { _logger.LogError("Workflow {0} raised error on step {1} Message: {2}", workflow.Id, pointer.StepId, ex.Message); wfResult.Errors.Add(new ExecutionError() { WorkflowId = workflow.Id, ExecutionPointerId = pointer.Id, ErrorTime = _datetimeProvider.Now.ToUniversalTime(), Message = ex.Message }); _executionResultProcessor.HandleStepException(workflow, def, pointer, step, ex); Host.ReportStepError(workflow, step, ex); } _cancellationProcessor.ProcessCancellations(workflow, def, wfResult); } ProcessAfterExecutionIteration(workflow, def, wfResult); DetermineNextExecutionTime(workflow); return(wfResult); }
internal void StartChain(string flowName, IInvocation invocation) { StepExecutionContext context = new StepExecutionContext { Invocation = invocation }; StartChain(flowName, context); }
public Task PersistWorkflowInstanceAsync(WorkflowInstance wfi, StepExecutionContext context, ExecutionResult executionResult, long elapsedMilliseconds, CancellationToken stoppingToken) { _logger.LogInformation($"{wfi.WorkflowId} 执行结果:{executionResult.Proceed}"); return(Task.CompletedTask); }
public async Task Execute(WorkflowInstance workflow, IPersistenceProvider persistenceStore, WorkflowOptions options) { //TODO: split this method up List <ExecutionPointer> exePointers = new List <ExecutionPointer>(workflow.ExecutionPointers.Where(x => x.Active && (!x.SleepUntil.HasValue || x.SleepUntil < DateTime.Now.ToUniversalTime()))); var def = _registry.GetDefinition(workflow.WorkflowDefinitionId, workflow.Version); if (def == null) { _logger.LogError("Workflow {0} version {1} is not registered", workflow.WorkflowDefinitionId, workflow.Version); return; } foreach (var pointer in exePointers) { var step = def.Steps.First(x => x.Id == pointer.StepId); if (step != null) { try { if (step.InitForExecution(_host, persistenceStore, def, workflow, pointer) == ExecutionPipelineDirective.Defer) { continue; } if (!pointer.StartTime.HasValue) { pointer.StartTime = DateTime.Now; } _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id); IStepBody body; if (step is WorkflowStepInline) { body = new InlineStepBody((step as WorkflowStepInline).Body); } else { body = (_serviceProvider.GetService(step.BodyType) as IStepBody); if (body == null) { var stepCtor = step.BodyType.GetConstructor(new Type[] { }); if (stepCtor != null) { body = (stepCtor.Invoke(null) as IStepBody); } } if (body == null) { _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString()); pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval); pointer.Errors.Add(new ExecutionError() { Id = Guid.NewGuid().ToString(), ErrorTime = DateTime.Now.ToUniversalTime(), Message = String.Format("Unable to construct step body {0}", step.BodyType.ToString()) }); continue; } } foreach (var input in step.Inputs) { var member = (input.Target.Body as MemberExpression); var resolvedValue = input.Source.Compile().DynamicInvoke(workflow.Data); step.BodyType.GetProperty(member.Member.Name).SetValue(body, resolvedValue); } IStepExecutionContext context = new StepExecutionContext() { Workflow = workflow, Step = step, PersistenceData = pointer.PersistenceData }; if (step.BeforeExecute(_host, persistenceStore, context, pointer, body) == ExecutionPipelineDirective.Defer) { continue; } var result = body.Run(context); foreach (var output in step.Outputs) { var member = (output.Target.Body as MemberExpression); var resolvedValue = output.Source.Compile().DynamicInvoke(body); var data = workflow.Data; data.GetType().GetProperty(member.Member.Name).SetValue(data, resolvedValue); } if (result.Proceed) { pointer.Active = false; pointer.EndTime = DateTime.Now; int forkCounter = 1; bool noOutcomes = true; foreach (var outcome in step.Outcomes.Where(x => object.Equals(x.Value, result.OutcomeValue))) { workflow.ExecutionPointers.Add(new ExecutionPointer() { Id = Guid.NewGuid().ToString(), StepId = outcome.NextStep, Active = true, ConcurrentFork = (forkCounter * pointer.ConcurrentFork), StepName = def.Steps.First(x => x.Id == outcome.NextStep).Name }); noOutcomes = false; forkCounter++; } pointer.PathTerminator = noOutcomes; } else { pointer.PersistenceData = result.PersistenceData; if (result.SleepFor.HasValue) { pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(result.SleepFor.Value); } } step.AfterExecute(_host, persistenceStore, context, result, pointer); } catch (Exception ex) { _logger.LogError("Workflow {0} raised error on step {1} Message: {2}", workflow.Id, pointer.StepId, ex.Message); pointer.Errors.Add(new ExecutionError() { Id = Guid.NewGuid().ToString(), ErrorTime = DateTime.Now.ToUniversalTime(), Message = ex.Message }); switch (step.ErrorBehavior ?? def.DefaultErrorBehavior) { case WorkflowErrorHandling.Retry: pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(step.RetryInterval ?? def.DefaultErrorRetryInterval ?? options.ErrorRetryInterval); break; case WorkflowErrorHandling.Suspend: workflow.Status = WorkflowStatus.Suspended; break; case WorkflowErrorHandling.Terminate: workflow.Status = WorkflowStatus.Terminated; break; } _host.ReportStepError(workflow, step, ex); } await persistenceStore.PersistWorkflow(workflow); } else { _logger.LogError("Unable to find step {0} in workflow definition", pointer.StepId); pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval); pointer.Errors.Add(new ExecutionError() { ErrorTime = DateTime.Now.ToUniversalTime(), Message = String.Format("Unable to find step {0} in workflow definition", pointer.StepId) }); } } DetermineNextExecutionTime(workflow); await persistenceStore.PersistWorkflow(workflow); }
public async Task Execute(WorkflowInstance workflow, IPersistenceProvider persistenceStore, WorkflowOptions options) { List <ExecutionPointer> exePointers = new List <ExecutionPointer>(workflow.ExecutionPointers.Where(x => x.Active && (!x.SleepUntil.HasValue || x.SleepUntil < DateTime.Now.ToUniversalTime()))); var def = _registry.GetDefinition(workflow.WorkflowDefinitionId, workflow.Version); if (def == null) { _logger.LogError("Workflow {0} version {1} is not registered", workflow.WorkflowDefinitionId, workflow.Version); return; } foreach (var pointer in exePointers) { var step = def.Steps.First(x => x.Id == pointer.StepId); if (step != null) { try { if ((step is ISubscriptionStep) && (!pointer.EventPublished)) { pointer.EventKey = (step as ISubscriptionStep).EventKey; pointer.EventName = (step as ISubscriptionStep).EventName; pointer.Active = false; await persistenceStore.PersistWorkflow(workflow); await _host.SubscribeEvent(workflow.Id, pointer.StepId, pointer.EventName, pointer.EventKey); continue; } if (!pointer.StartTime.HasValue) { pointer.StartTime = DateTime.Now; } _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id); IStepBody body; if (step is WorkflowStepInline) { body = new InlineStepBody((step as WorkflowStepInline).Body); } else { body = (_serviceProvider.GetService(step.BodyType) as IStepBody); if (body == null) { var stepCtor = step.BodyType.GetConstructor(new Type[] { }); if (stepCtor != null) { body = (stepCtor.Invoke(null) as IStepBody); } } if (body == null) { _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString()); pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval); pointer.Errors.Add(new ExecutionError() { ErrorTime = DateTime.Now.ToUniversalTime(), Message = String.Format("Unable to construct step body {0}", step.BodyType.ToString()) }); continue; } } foreach (var input in step.Inputs) { var member = (input.Target.Body as MemberExpression); var resolvedValue = input.Source.Compile().DynamicInvoke(workflow.Data); step.BodyType.GetProperty(member.Member.Name).SetValue(body, resolvedValue); } if ((body is ISubscriptionBody) && (pointer.EventPublished)) { (body as ISubscriptionBody).EventData = pointer.EventData; } IStepExecutionContext context = new StepExecutionContext() { Workflow = workflow, Step = step, PersistenceData = pointer.PersistenceData }; var result = body.Run(context); foreach (var output in step.Outputs) { var member = (output.Target.Body as MemberExpression); var resolvedValue = output.Source.Compile().DynamicInvoke(body); var data = workflow.Data; data.GetType().GetProperty(member.Member.Name).SetValue(data, resolvedValue); } if (result.Proceed) { pointer.Active = false; pointer.EndTime = DateTime.Now; foreach (var outcome in step.Outcomes.Where(x => object.Equals(x.Value, result.OutcomeValue))) { workflow.ExecutionPointers.Add(new ExecutionPointer() { StepId = outcome.NextStep, Active = true }); } } else { pointer.PersistenceData = result.PersistenceData; if (result.SleepFor.HasValue) { pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(result.SleepFor.Value); } } } catch (Exception ex) { _logger.LogError("Workflow {0} raised error on step {1} Message: {2}", workflow.Id, pointer.StepId, ex.Message); pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval); pointer.Errors.Add(new ExecutionError() { ErrorTime = DateTime.Now.ToUniversalTime(), Message = ex.Message }); } await persistenceStore.PersistWorkflow(workflow); } else { _logger.LogError("Unable to find step {0} in workflow definition", pointer.StepId); pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval); pointer.Errors.Add(new ExecutionError() { ErrorTime = DateTime.Now.ToUniversalTime(), Message = String.Format("Unable to find step {0} in workflow definition", pointer.StepId) }); } } DetermineNextExecutionTime(workflow); await persistenceStore.PersistWorkflow(workflow); }
private async Task ExecuteAsync(WorkflowInstance wfi, CancellationToken stoppingToken) { using var scope = _serviceProvider.CreateScope(); var context = new StepExecutionContext() { StoppingToken = stoppingToken, ServiceProvider = _serviceProvider, Logger = _logger, ContextData = wfi.Data }; var executionResult = new ExecutionResult(); var sw = new Stopwatch(); try { _options?.Start?.Invoke(scope.ServiceProvider, wfi); var steps = scope.ServiceProvider.GetServices <IStepBodyAsync>().ToList(); _logger.LogInformation($"{wfi.Id} Begin"); sw.Start(); if (!steps.Any()) { throw new WorkflowStepNotRegisteredException(wfi.WorkflowId, wfi.Version); } foreach (var workFlowStep in wfi.Steps) { var retryCnt = 0; context.CurrentStep = workFlowStep; var stepBody = steps.FirstOrDefault(m => m.GetType() == workFlowStep.StepType); if (stepBody == null) { throw new NullReferenceException(workFlowStep?.StepType?.FullName); } _logger.LogInformation($"{workFlowStep.Id}, Begin"); var inComeData = context.ContextData; // retry step when fail while (retryCnt++ <= Math.Abs(context.CurrentStep.FailedRetryCount)) { executionResult = await stepBody.RunAsync(context, stoppingToken); if (executionResult.Proceed) { break; } } var outComeData = context.ContextData; // persistent current step data & status await _persistenceProvider.PersistWorkflowStepAsync(wfi.Id, wfi.WorkflowId, workFlowStep, inComeData, outComeData, executionResult, stoppingToken); if (!executionResult.Proceed) { _logger.LogError( $"{workFlowStep.Id}, retryCount: {retryCnt - 1}, error:{executionResult.InnerException.Message}"); break; } _logger.LogInformation($"{workFlowStep.Id}, End"); _logger.LogInformation( $"{workFlowStep.Id}, {executionResult.ConsumeElapsedMilliseconds} ms"); } sw.Stop(); if (!executionResult.Proceed) { _logger.LogError($"{wfi.Id}, End With Exception: {executionResult.InnerException}"); } _logger.LogInformation($"{wfi.Id}, End and Execute: {sw.ElapsedMilliseconds} ms"); } catch (System.Exception e) { _logger.LogError(e.Message, e); executionResult.Proceed = false; executionResult.InnerException = e; } finally { await _persistenceProvider.PersistWorkflowInstanceAsync(wfi, context, executionResult, sw.ElapsedMilliseconds, stoppingToken); _options?.End?.Invoke(scope.ServiceProvider, wfi, context, executionResult); } }