Exemplo n.º 1
0
        public override Task <UpdateStepRequest> HandleStep(Step step)
        {
            var updateRequest = new UpdateStepRequest()
            {
                Id = step.Id
            };

            switch (step.StepTemplateId)
            {
            case "Fibonacci_stepTemplate:0":
                var completeStep = true;
                if (testSuspension)
                {
                    var n = random.Next(0, 2);
                    if (n == 1)
                    {
                        completeStep = false;
                    }


                    var logSuccessfullySent = SendStepLog(step.Id, "Test").GetAwaiter().GetResult();
                }
                if (completeStep)
                {
                    var result = CalculateFibonacci((Int64)DynamicDataUtility.GetData(step.Inputs, "n-1").Value, (Int64)(DynamicDataUtility.GetData(step.Inputs, "n-2").Value));
                    updateRequest.Outputs = new Dictionary <string, object>()
                    {
                        { "n", result }
                    };
                    updateRequest.Status = StepStatuses.Successful;
                    return(Task.FromResult(updateRequest));
                }
                else
                {
                    updateRequest.Status = StepStatuses.Suspended;
                    return(Task.FromResult(updateRequest));
                }

            case "Pass_Password:0":
                if (((string)(DynamicDataUtility.GetData(step.Inputs, "secret").Value) == "This is a test"))
                {
                    {
                        updateRequest.Outputs = new Dictionary <string, object>()
                        {
                            { "secret", (string)(DynamicDataUtility.GetData(step.Inputs, "secret").Value) }
                        };
                        updateRequest.Status = StepStatuses.Successful;
                        return(Task.FromResult(updateRequest));
                    }
                }
                else
                {
                    throw new Exception("Failed to get password.");
                }
            }

            throw new NotImplementedException();
        }
Exemplo n.º 2
0
        public async Task <CommandResult <Workflow> > Handle(CreateWorkflowCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            WorkflowTemplate template = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wft => wft.ReferenceId == request.WorkflowTemplateId);

            if (template == null)
            {
                throw new WorkflowTemplateNotFoundException("Workflow Template " + request.WorkflowTemplateId + " not found.");
            }

            if (template.InputDefinitions.Count() < request.Inputs.Count())
            {
                throw new InvalidInputsException("Invalid number of inputs, number passed was " + request.Inputs.Count() + " which is less then defined " + template.InputDefinitions.Count());
            }

            var verifiedWorkflowInputs = new Dictionary <string, object>();

            if (template.InputDefinitions != null)
            {
                foreach (var input in template.InputDefinitions)
                {
                    if (!request.Inputs.ContainsKey(input.Key))
                    {
                        throw new MissingInputException("Workflow input data is missing " + input.Key);
                    }
                }

                foreach (var input in request.Inputs)
                {
                    if (template.InputDefinitions.ContainsKey(input.Key) && template.InputDefinitions[input.Key].Type == InputDataTypes.Secret && !InputDataUtility.IsInputReference(input, out _, out _))
                    {
                        verifiedWorkflowInputs.Add(input.Key.ToLower(), SecurityUtility.SymmetricallyEncrypt((string)input.Value, ClusterStateService.GetEncryptionKey()));
                    }
                    else
                    {
                        verifiedWorkflowInputs.Add(input.Key.ToLower(), input.Value);
                    }
                }
            }

            var createdWorkflowId  = Guid.NewGuid();
            var startingLogicBlock = template.LogicBlocks.Where(lb => lb.Value.Dependencies.Evaluate(new List <Step>())).ToList();

            var createdWorkflowTemplateId = await _node.Handle(new AddShardWriteOperation()
            {
                Data = new Domain.Entities.Workflows.Workflow(
                    createdWorkflowId,
                    request.WorkflowTemplateId,
                    verifiedWorkflowInputs, //Encrypted inputs
                    request.Name,
                    request.CreatedBy,
                    DateTime.UtcNow,
                    request.ExecutionTemplateId,
                    request.ExecutionScheduleId
                    ),
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });

            var workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == createdWorkflowId);

            //When there are no conditions to be met

            // Needs to happen before first step is added
            DateTimeOffset WorkflowStartTime = DateTime.Now;

            foreach (var block in startingLogicBlock)
            {
                try
                {
                    foreach (var subBlock in block.Value.SubsequentSteps)
                    {
                        var newStepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == subBlock.Value.StepTemplateId);

                        if (newStepTemplate == null)
                        {
                            throw new StepTemplateNotFoundException("Template " + subBlock.Value.StepTemplateId + " not found.");
                        }

                        var verifiedInputs = new Dictionary <string, object>();

                        foreach (var mapping in subBlock.Value.Mappings)
                        {
                            string mappedValue = "";
                            if ((mapping.Value.DefaultValue != null && (mapping.Value.OutputReferences == null || mapping.Value.OutputReferences.Count() == 0)) || (mapping.Value.DefaultValue != null && mapping.Value.OutputReferences.First() != null && mapping.Value.DefaultValue.Priority > mapping.Value.OutputReferences.First().Priority))
                            {
                                // Change the ID to match the output
                                verifiedInputs.Add(mapping.Key, mapping.Value.DefaultValue.Value);
                            }
                            else if (mapping.Value.OutputReferences != null)
                            {
                                verifiedInputs.Add(mapping.Key, DynamicDataUtility.GetData(request.Inputs, mapping.Value.OutputReferences.First().OutputId).Value);
                            }
                        }

                        await _mediator.Send(new CreateStepCommand()
                        {
                            StepTemplateId = subBlock.Value.StepTemplateId,
                            CreatedBy      = SystemUsers.QUEUE_MANAGER,
                            Description    = null,
                            Inputs         = verifiedInputs,
                            WorkflowId     = createdWorkflowId,
                            Name           = subBlock.Key
                        });
                    }


                    workflow.UpdateJournal(
                        new JournalEntry()
                    {
                        CreatedBy = request.CreatedBy,
                        CreatedOn = DateTime.UtcNow,
                        Updates   = new List <Update>()
                        {
                            new Update()
                            {
                                FieldName = "completedlogicblocks",
                                Type      = UpdateType.Append,
                                Value     = block.Key //Add the logic block
                            }
                        }
                    });

                    await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = workflow,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                    });
                }
                catch (Exception e)
                {
                    _logger.LogCritical("Failed to action logic block " + block.Key + " with error " + e.Message + Environment.NewLine + e.StackTrace);
                }
            }

            stopwatch.Stop();

            return(new CommandResult <Workflow>()
            {
                Result = workflow,
                ObjectRefId = createdWorkflowId.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create
            });
        }
Exemplo n.º 3
0
        public async override Task <UpdateStepRequest> HandleStep(Step step)
        {
            var updateRequest = new UpdateStepRequest()
            {
                Id = step.Id
            };

            switch (step.StepTemplateId)
            {
            case "_GenerateSystemReport:0":
                var totalStepCount = (await _mediator.Send(new GetEntitiesQuery <Step>
                {
                    Page = 0,
                    Size = 0,
                })).Count;

                var totalUnassignedStepCount = (await _mediator.Send(new GetEntitiesQuery <Step>
                {
                    Page = 0,
                    Size = 0,
                    Expression = e => e.Status == StepStatuses.Unassigned
                })).Count;

                var totalActiveBotCount = (await _mediator.Send(new GetEntitiesQuery <BotKey>
                {
                    Page = 0,
                    Size = 0,
                    Expression = e => e.IsDisabled == false
                })).Count;

                updateRequest.Outputs = new Dictionary <string, object>()
                {
                    { "report", "Total Steps: " + totalStepCount + ", Total Unassigned Steps:" + totalUnassignedStepCount + ", Total Active Bots: " + totalActiveBotCount },
                    { "slack_report", JsonConvert.SerializeObject(new[]
                        {
                            new
                            {
                                type   = "section",
                                fields = new[] {
                                    new {
                                        text = "Total Unassigned Steps: " + totalUnassignedStepCount,
                                        type = "mrkdwn"
                                    }
                                }
                            },
                            new
                            {
                                type   = "section",
                                fields = new[] {
                                    new {
                                        text = "Total Steps: " + totalStepCount,
                                        type = "mrkdwn"
                                    }
                                }
                            },
                            new
                            {
                                type   = "section",
                                fields = new[] {
                                    new {
                                        text = "Total Active Bots: " + totalActiveBotCount,
                                        type = "mrkdwn"
                                    }
                                }
                            }
                        }) },
                    { "markdown", "" }
                };

                updateRequest.Status     = StepStatuses.Successful;
                updateRequest.StatusCode = 0;
                return(updateRequest);

            case "_SendSlackMessage:0":
                var client = new SlackClient(_clientFactory);
                await client.PostMessage((string)DynamicDataUtility.GetData(step.Inputs, "webhook_url").Value, new
                {
                    username   = (string)DynamicDataUtility.GetData(step.Inputs, "from").Value,
                    icon_emoji = step.Inputs.ContainsKey("icon_emoji") ? (string)DynamicDataUtility.GetData(step.Inputs, "icon_emoji").Value : null,
                    icon_url   = step.Inputs.ContainsKey("icon_url") ? (string)DynamicDataUtility.GetData(step.Inputs, "icon_url").Value : null,
                    channel    = step.Inputs.ContainsKey("channel") ? (string)DynamicDataUtility.GetData(step.Inputs, "channel").Value : null,
                    blocks     = step.Inputs.ContainsKey("blocks") ? JsonConvert.DeserializeObject((string)DynamicDataUtility.GetData(step.Inputs, "blocks").Value) : null,
                    text       = step.Inputs.ContainsKey("text") ? (string)DynamicDataUtility.GetData(step.Inputs, "text").Value : null
                });

                updateRequest.Status = StepStatuses.Successful;
                return(updateRequest);
            }

            updateRequest.Status = StepStatuses.Error;
            updateRequest.Log    = "Bot does not have a catch for " + step.StepTemplateId;
            return(updateRequest);
        }
Exemplo n.º 4
0
        public async Task <CommandResult> Handle(ScanWorkflowCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            List <string> messages             = new List <string>();
            bool          workflowStillRunning = false;

            var workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == request.WorkflowId);

            if (workflow == null)
            {
                throw new MissingWorkflowException("Failed to find workflow " + request.WorkflowId + " as workflow does not exist.");
            }

            //Get the workflow template
            var workflowTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wt => wt.ReferenceId == workflow.WorkflowTemplateId);

            if (workflowTemplate == null)
            {
                throw new WorkflowTemplateNotFoundException("Failed to scan workflow " + request.WorkflowId + " workflow template " + workflow.WorkflowTemplateId + ".");
            }

            //Get all the steps related to this task
            var workflowSteps = (await _entitiesRepository.GetAsync <Step>(s => s.WorkflowId == request.WorkflowId)).ToList();

            foreach (var workflowStep in workflowSteps)
            {
                workflowStep.Outputs = DynamicDataUtility.DecryptDynamicData((await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == workflowStep.StepTemplateId)).OutputDefinitions, workflowStep.Outputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());
                if (!workflowStep.IsComplete())
                {
                    messages.Add("Workflow step " + workflowStep.Id + " (" + workflowStep.Name + ")" + " is running.");
                    workflowStillRunning = true;
                }
            }

            bool stepCreated = false;

            if (!workflowStillRunning)
            {
                if (workflow.CompletedLogicBlocks == null)
                {
                    workflow.CompletedLogicBlocks = new List <string>();
                }

                //Evaluate all logic blocks that have not been completed
                var logicBlocks = workflowTemplate.LogicBlocks.Where(lb => !workflow.CompletedLogicBlocks.Contains(lb.Key)).ToList();

                foreach (var logicBlock in logicBlocks)
                {
                    var  lockId       = Guid.NewGuid();
                    bool lockObtained = false;
                    while (!lockObtained)
                    {
                        while (_clusterStateService.IsLogicBlockLocked(request.WorkflowId, logicBlock.Key))
                        {
                            Console.WriteLine("Found " + ("workflow:" + request.WorkflowId + ">logicBlock:" + logicBlock) + " Lock");
                            await Task.Delay(1000);
                        }

                        int entryNumber = await _clusterStateService.LockLogicBlock(lockId, request.WorkflowId, logicBlock.Key);

                        //Check whether you got the lock
                        lockObtained = _clusterStateService.WasLockObtained(lockId, request.WorkflowId, logicBlock.Key);
                    }

                    //When the logic block is released, recheck whether this logic block has been evaluated
                    workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == request.WorkflowId);

                    workflow.Inputs = DynamicDataUtility.DecryptDynamicData(workflowTemplate.InputDefinitions, workflow.Inputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());


                    if (workflow.CompletedLogicBlocks == null)
                    {
                        workflow.CompletedLogicBlocks = new List <string>();
                    }

                    //If the logic block is ready to be processed, submit the steps
                    if (logicBlock.Value.Dependencies.Evaluate(workflowSteps) && !workflow.CompletedLogicBlocks.Contains(logicBlock.Key))
                    {
                        foreach (var substep in logicBlock.Value.SubsequentSteps)
                        {
                            if (workflowSteps.Where(s => s.Name == substep.Key).Count() == 0)
                            {
                                var verifiedInputs = new Dictionary <string, object>();

                                foreach (var mapping in substep.Value.Mappings)
                                {
                                    //find the mapping with the highest priority
                                    var highestPriorityReference = WorkflowTemplateUtility.GetHighestPriorityReference(mapping.Value.OutputReferences, workflowSteps.ToArray());
                                    //if the highest priority reference is null, there are no mappings
                                    if (highestPriorityReference == null && mapping.Value.DefaultValue == null)
                                    {
                                    }
                                    // If default value is higher priority
                                    else if (mapping.Value.DefaultValue != null && (highestPriorityReference == null || highestPriorityReference.Priority < mapping.Value.DefaultValue.Priority))
                                    {
                                        verifiedInputs.Add(mapping.Key, mapping.Value.DefaultValue.Value);
                                    }
                                    // If the step ref is not -1 it is a step in the array but the workflow
                                    else if (highestPriorityReference.StepName != ReservedValues.WorkflowStartStepName)
                                    {
                                        var parentStep = workflowSteps.Where(ss => ss.Name == highestPriorityReference.StepName).FirstOrDefault();

                                        //If there is a AND and there is no parent step, throw a error
                                        if (parentStep == null)
                                        {
                                            throw new InvalidWorkflowProcessingException("Missing source for mapping " + mapping.Key + " from step " + highestPriorityReference.StepName);
                                        }
                                        else
                                        {
                                            if (parentStep != null)
                                            {
                                                try
                                                {
                                                    // Get the output value based on the pre-requisite id
                                                    var outPutValue = DynamicDataUtility.GetData(parentStep.Outputs, highestPriorityReference.OutputId);
                                                    // Validate it is in the definition
                                                    verifiedInputs.Add(mapping.Key, outPutValue.Value);
                                                }
                                                catch (Exception e)
                                                {
                                                    //TO DO Move this to logger
                                                    Console.WriteLine("Found error at mapping " + mapping.Key + " for step " + substep.Key);
                                                    throw e;
                                                }
                                            }
                                        }
                                    }
                                    //Get the value from the workflow ref
                                    else
                                    {
                                        // Validate it is in the definition
                                        verifiedInputs.Add(mapping.Key, DynamicDataUtility.GetData(workflow.Inputs, highestPriorityReference.OutputId).Value);
                                    }
                                }
                                stepCreated = true;
                                //Add the step TODO, add step priority
                                await _mediator.Send(new CreateStepCommand()
                                {
                                    StepTemplateId = substep.Value.StepTemplateId,
                                    CreatedBy      = SystemUsers.QUEUE_MANAGER,
                                    Inputs         = verifiedInputs,
                                    WorkflowId     = workflow.Id,
                                    Name           = substep.Key //create the step with the right subsequent step
                                });

                                messages.Add("Started workflow step " + substep.Key);
                            }
                        }

                        //Mark it as evaluated
                        workflow.UpdateJournal(
                            new JournalEntry()
                        {
                            CreatedBy = request.CreatedBy,
                            CreatedOn = DateTime.UtcNow,
                            Updates   = new List <Update>()
                            {
                                new Update()
                                {
                                    FieldName = "completedlogicblocks",
                                    Type      = UpdateType.Append,
                                    Value     = logicBlock.Key
                                }
                            }
                        });

                        //await _workflowsRepository.UpdateWorkflow(workflow);
                        await _node.Handle(new AddShardWriteOperation()
                        {
                            Data             = workflow,
                            WaitForSafeWrite = true,
                            Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                        });
                    }
                    await _clusterStateService.UnlockLogicBlock(lockId, request.WorkflowId, logicBlock.Key);
                }

                //Check if there are no longer any steps that are unassigned or assigned

                var workflowStatus = workflow.Status;
                workflowSteps = (await _entitiesRepository.GetAsync <Step>(s => s.WorkflowId == request.WorkflowId)).ToList();
                var highestStatus     = StepStatuses.GetHighestPriority(workflowSteps.Select(s => s.Status).ToArray());
                var newWorkflowStatus = stepCreated ? WorkflowStatuses.ConvertStepStatusToWorkflowStatus(StepStatuses.Unassigned) : WorkflowStatuses.ConvertStepStatusToWorkflowStatus(highestStatus);

                if (newWorkflowStatus != workflow.Status)
                {
                    workflow.UpdateJournal(
                        new JournalEntry()
                    {
                        CreatedBy = request.CreatedBy,
                        CreatedOn = DateTime.UtcNow,
                        Updates   = new List <Update>()
                        {
                            new Update()
                            {
                                FieldName = "status",
                                Type      = UpdateType.Override,
                                Value     = newWorkflowStatus
                            }
                        }
                    });

                    //await _workflowsRepository.UpdateWorkflow(workflow);
                    await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = workflow,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                    });


                    messages.Add("Updated workflow status " + newWorkflowStatus + ".");
                }
            }

            return(new CommandResult()
            {
                ObjectRefId = request.WorkflowId.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Update,
                IsSuccessful = true,
                Messages = messages.ToArray()
            });
        }