protected override async Task ProcessItem(string itemId, CancellationToken cancellationToken) { if (!await _lockProvider.AcquireLock(itemId, cancellationToken)) { Logger.LogInformation("Workflow locked {0}", itemId); return; } WorkflowInstance workflow = null; WorkflowExecutorResult result = null; try { cancellationToken.ThrowIfCancellationRequested(); workflow = await _persistenceStore.GetWorkflowInstance(itemId, cancellationToken); if (workflow.Status == WorkflowStatus.Runnable) { try { result = await _executor.Execute(workflow, cancellationToken); } finally { await _persistenceStore.PersistWorkflow(workflow, cancellationToken); await QueueProvider.QueueWork(itemId, QueueType.Index); _greylist.Remove($"wf:{itemId}"); } } } finally { await _lockProvider.ReleaseLock(itemId); if ((workflow != null) && (result != null)) { foreach (var sub in result.Subscriptions) { await SubscribeEvent(sub, _persistenceStore, cancellationToken); } await _persistenceStore.PersistErrors(result.Errors, cancellationToken); if ((workflow.Status == WorkflowStatus.Runnable) && workflow.NextExecution.HasValue) { var readAheadTicks = _datetimeProvider.UtcNow.Add(Options.PollInterval).Ticks; if (workflow.NextExecution.Value < readAheadTicks) { new Task(() => FutureQueue(workflow, cancellationToken)).Start(); } else { if (_persistenceStore.SupportsScheduledCommands) { await _persistenceStore.ScheduleCommand(new ScheduledCommand() { CommandName = ScheduledCommand.ProcessWorkflow, Data = workflow.Id, ExecuteTime = workflow.NextExecution.Value }); } } } } } }
public async Task <WorkflowInstance> RunWorkflowSync <TData>(string workflowId, int version, TData data, string reference, CancellationToken token, bool persistSate = true) where TData : new() { var def = _registry.GetDefinition(workflowId, version); if (def == null) { throw new WorkflowNotRegisteredException(workflowId, version); } var wf = new WorkflowInstance { WorkflowDefinitionId = workflowId, Version = def.Version, Data = data, Description = def.Description, NextExecution = 0, CreateTime = _dateTimeProvider.UtcNow, Status = WorkflowStatus.Suspended, Reference = reference }; if ((def.DataType != null) && (data == null)) { if (typeof(TData) == def.DataType) { wf.Data = new TData(); } else { wf.Data = def.DataType.GetConstructor(new Type[0]).Invoke(new object[0]); } } wf.ExecutionPointers.Add(_pointerFactory.BuildGenesisPointer(def)); var id = Guid.NewGuid().ToString(); if (persistSate) { id = await _persistenceStore.CreateNewWorkflow(wf); } else { wf.Id = id; } wf.Status = WorkflowStatus.Runnable; if (!await _lockService.AcquireLock(id, CancellationToken.None)) { throw new InvalidOperationException(); } try { while ((wf.Status == WorkflowStatus.Runnable) && !token.IsCancellationRequested) { await _executor.Execute(wf); if (persistSate) { await _persistenceStore.PersistWorkflow(wf); } } } finally { await _lockService.ReleaseLock(id); } if (persistSate) { await _queueService.QueueWork(id, QueueType.Index); } return(wf); }
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); }
/// <summary> /// Worker thread body /// </summary> private async void RunWorkflows() { while (!_shutdown) { try { var workflowId = await _queueProvider.DequeueWork(QueueType.Workflow); if (workflowId != null) { try { if (await _lockProvider.AcquireLock(workflowId)) { WorkflowInstance workflow = null; WorkflowExecutorResult result = null; try { workflow = await _persistenceStore.GetWorkflowInstance(workflowId); if (workflow.Status == WorkflowStatus.Runnable) { try { result = _executor.Execute(workflow, _options); } finally { await _persistenceStore.PersistWorkflow(workflow); } } } finally { await _lockProvider.ReleaseLock(workflowId); if ((workflow != null) && (result != null)) { foreach (var sub in result.Subscriptions) { await SubscribeEvent(sub); } await _persistenceStore.PersistErrors(result.Errors); if ((workflow.Status == WorkflowStatus.Runnable) && workflow.NextExecution.HasValue && workflow.NextExecution.Value < DateTime.Now.ToUniversalTime().Ticks) { await _queueProvider.QueueWork(workflowId, QueueType.Workflow); } } } } else { _logger.LogInformation("Workflow locked {0}", workflowId); } } catch (Exception ex) { _logger.LogError(ex.Message); } } else { await Task.Delay(_options.IdleTime); //no work } } catch (Exception ex) { _logger.LogError(ex.Message); } } }
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); }