Esempio n. 1
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int version, TData data)
        {
            if (_shutdown)
            {
                throw new Exception("Host is not running");
            }

            var def = _registry.GetDefinition(workflowId, version);

            if (def == null)
            {
                throw new Exception(String.Format("Workflow {0} version {1} is not registered", workflowId, version));
            }

            var wf = new WorkflowInstance();

            wf.WorkflowDefinitionId = workflowId;
            wf.Version       = version;
            wf.Data          = data;
            wf.Description   = def.Description;
            wf.NextExecution = 0;
            wf.Status        = WorkflowStatus.Runnable;
            wf.ExecutionPointers.Add(new ExecutionPointer()
            {
                StepId = def.InitialStep, Active = true
            });
            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueForProcessing(id);

            return(id);
        }
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null)
            where TData : class
        {
            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    = DateTime.Now.ToUniversalTime(),
                Status        = WorkflowStatus.Runnable
            };

            if ((def.DataType != null) && (data == null))
            {
                wf.Data = TypeExtensions.GetConstructor(def.DataType, new Type[] { }).Invoke(null);
            }

            wf.ExecutionPointers.Add(_pointerFactory.BuildGenesisPointer(def));

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            return(id);
        }
Esempio n. 3
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null, string reference = null)
            where TData : class, 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.Runnable,
                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));

            using (var scope = _serviceProvider.CreateScope())
            {
                var middlewareRunner = scope.ServiceProvider.GetRequiredService <IWorkflowMiddlewareRunner>();
                await middlewareRunner.RunPreMiddleware(wf, def);
            }

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            await _queueProvider.QueueWork(id, QueueType.Index);

            await _eventHub.PublishNotification(new WorkflowStarted
            {
                EventTimeUtc         = _dateTimeProvider.UtcNow,
                Reference            = reference,
                WorkflowInstanceId   = id,
                WorkflowDefinitionId = def.Id,
                Version = def.Version
            });

            return(id);
        }
Esempio n. 4
0
        public async Task <IActionResult> Post(string workflowName, int?version, string document)
        {
            var def = _registry.GetDefinition(workflowName, version);

            if (def == null)
            {
                return(BadRequest($"Workflow definition {workflowName} for version {version} not found"));
            }

            var workflowId = await _workflowService.StartWorkflow(
                workflowName,
                version,
                data : new UntypedDocumentWorkflowData {
                Document = document
            });

            return(Ok(workflowId));
        }
Esempio n. 5
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null, string reference = null)
            where TData : class, 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    = DateTime.Now.ToUniversalTime(),
                Status        = WorkflowStatus.Runnable,
                Reference     = reference
            };

            if ((def.DataType != null) && (data == null))
            {
                wf.Data = new TData();
            }

            wf.ExecutionPointers.Add(_pointerFactory.BuildGenesisPointer(def));

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            await _eventHub.PublishNotification(new WorkflowStarted()
            {
                EventTimeUtc         = DateTime.UtcNow,
                Reference            = reference,
                WorkflowInstanceId   = id,
                WorkflowDefinitionId = def.Id,
                Version = def.Version
            });

            return(id);
        }
Esempio n. 6
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null)
            where TData : class
        {
            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    = DateTime.Now.ToUniversalTime(),
                Status        = WorkflowStatus.Runnable
            };

            if ((def.DataType != null) && (data == null))
            {
                wf.Data = TypeExtensions.GetConstructor(def.DataType, new Type[] { }).Invoke(null);
            }

            wf.ExecutionPointers.Add(new ExecutionPointer
            {
                Id       = Guid.NewGuid().ToString(),
                StepId   = 0,
                Active   = true,
                StepName = Enumerable.First <WorkflowStep>(def.Steps, x => x.Id == 0).Name
            });

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            return(id);
        }
        public async Task <IActionResult> Post(string id, int?version, [FromBody] JObject data)
        {
            string workflowId = null;
            var    def        = _registry.GetDefinition(id, version);

            if (def == null)
            {
                return(BadRequest(String.Format("Workflow defintion {0} for version {1} not found", id, version)));
            }
            if ((data != null) && (def.DataType != null))
            {
                var dataStr = JsonConvert.SerializeObject(data);
                var dataObj = JsonConvert.DeserializeObject(dataStr, def.DataType);
                workflowId = await _workflowHost.StartWorkflow(id, version, dataObj);
            }
            else
            {
                workflowId = await _workflowHost.StartWorkflow(id, version, null);
            }

            return(Ok(workflowId));
        }
        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, token);
            }
            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, token);

                    if (persistSate)
                    {
                        await _persistenceStore.PersistWorkflow(wf, token);
                    }
                }
            }
            finally
            {
                await _lockService.ReleaseLock(id);
            }

            if (persistSate)
            {
                await _queueService.QueueWork(id, QueueType.Index);
            }

            return(wf);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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);
            }

            _cancellationProcessor.ProcessCancellations(workflow, def, wfResult);

            foreach (var pointer in exePointers)
            {
                if (!pointer.Active)
                {
                    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            = $"Unable to find step {pointer.StepId} in workflow definition"
                    });
                    continue;
                }

                try
                {
                    if (!InitializeStep(workflow, step, wfResult, def, pointer))
                    {
                        continue;
                    }

                    await ExecuteStep(workflow, step, pointer, wfResult, def);
                }
                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);
        }
Esempio n. 11
0
        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);
        }
        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);
        }
Esempio n. 13
0
        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);
        }
Esempio n. 14
0
 public virtual WorkflowDefinition GetDefinition(string workflowId, int?version = null)
 {
     return(_registry.GetDefinition(workflowId, version));
 }