// Simple logic // Creates four activities at the begining // Waits for them to complete and completes the workflow static void Decider() { int activityCount = 0; // This refers to total number of activities per workflow IAmazonSimpleWorkflow swfClient = AWSClientFactory.CreateAmazonSimpleWorkflowClient(); while (true) { Console.WriteLine("Decider: Polling for decision task ..."); PollForDecisionTaskRequest request = new PollForDecisionTaskRequest() { Domain = domainName, TaskList = new TaskList() {Name = "HelloWorld"} }; PollForDecisionTaskResponse response = swfClient.PollForDecisionTask(request); if (response.DecisionTask.TaskToken == null) { Console.WriteLine("Decider: NULL"); continue; } int completedActivityTaskCount = 0, totalActivityTaskCount = 0; foreach (HistoryEvent e in response.DecisionTask.Events) { Console.WriteLine("Decider: EventType - " + e.EventType + ", EventId - " + e.EventId); if (e.EventType == "ActivityTaskCompleted") completedActivityTaskCount++; if (e.EventType.Value.StartsWith("Activity")) totalActivityTaskCount++; } Console.WriteLine(".... completedCount=" + completedActivityTaskCount); List<Decision> decisions = new List<Decision>(); if (totalActivityTaskCount == 0) // Create this only at the begining { ScheduleActivity("Activity1A", decisions); ScheduleActivity("Activity1B", decisions); ScheduleActivity("Activity2", decisions); ScheduleActivity("Activity2", decisions); activityCount = 4; } else if (completedActivityTaskCount == activityCount) { Decision decision = new Decision() { DecisionType = DecisionType.CompleteWorkflowExecution, CompleteWorkflowExecutionDecisionAttributes = new CompleteWorkflowExecutionDecisionAttributes { Result = "{\"Result\":\"WF Complete!\"}" } }; decisions.Add(decision); Console.WriteLine("Decider: WORKFLOW COMPLETE!!!!!!!!!!!!!!!!!!!!!!"); } RespondDecisionTaskCompletedRequest respondDecisionTaskCompletedRequest = new RespondDecisionTaskCompletedRequest() { Decisions = decisions, TaskToken = response.DecisionTask.TaskToken }; swfClient.RespondDecisionTaskCompleted(respondDecisionTaskCompletedRequest); } }
static void ScheduleActivity(string name, List<Decision> decisions) { Decision decision = new Decision() { DecisionType = DecisionType.ScheduleActivityTask, ScheduleActivityTaskDecisionAttributes = // Uses DefaultTaskList new ScheduleActivityTaskDecisionAttributes() { ActivityType = new ActivityType() { Name = name, Version = "2.0" }, ActivityId = name + "-" + System.Guid.NewGuid().ToString(), Input = "{\"activityInput1\":\"value1\"}" } }; Console.WriteLine("Decider: ActivityId=" + decision.ScheduleActivityTaskDecisionAttributes.ActivityId); decisions.Add(decision); }
/// <summary> /// Helper method to create a decision for completed workflow exeution. This happens once all the thumbnails have been created. /// </summary> /// <returns>Decision with ScheduleActivityTaskDecisionAttributes</returns> Decision CreateCompleteWorkflowExecutionDecision(List<Common.ActivityTaskCompletedResult> states) { // Create a string listing all the images create. StringBuilder sb = new StringBuilder(); states.ForEach(x => sb.AppendFormat("\tRequestActionId: {0} \r\n", x.RequestActionId)); Decision decision = new Decision() { DecisionType = DecisionType.CompleteWorkflowExecution, CompleteWorkflowExecutionDecisionAttributes = new CompleteWorkflowExecutionDecisionAttributes { Result = sb.ToString() } }; Console.WriteLine("Decision: Complete Workflow Execution"); Console.WriteLine(sb.ToString()); return decision; }
/// <summary> /// Helper method to create a decision for scheduling an activity /// </summary> /// <returns>Decision with ScheduleActivityTaskDecisionAttributes</returns> Decision CreateActivityDecision(Common.WorkflowExecutionStartedInput startingInput, int RequestActionId) { // setup the input for the activity task. Common.ActivityTaskCompletedResult state = new Common.ActivityTaskCompletedResult { StartingInput = startingInput, RequestActionId = RequestActionId }; Decision decision = new Decision() { DecisionType = DecisionType.ScheduleActivityTask, ScheduleActivityTaskDecisionAttributes = new ScheduleActivityTaskDecisionAttributes() { ActivityType = new Amazon.SimpleWorkflow.Model.ActivityType() { Name = "MinimalWorkflowActivityType1", Version = "5.0" }, ActivityId = "MinimalWorkflowActivityType1" + DateTime.Now.TimeOfDay, Input = Common.Utils.SerializeToJSON<Common.ActivityTaskCompletedResult>(state) } }; Console.WriteLine(string.Format("Decision: Schedule Activity Task (RequestId {0} to RequestActionId {1})", state.StartingInput.RequestId, RequestActionId)); return decision; }
List<Decision> DecideHelper(Common.WorkflowExecutionStartedInput startingInput, List<Common.ActivityTaskCompletedResult> activityStates) { List<Decision> decisions = new List<Decision>(); //the request should have a new state and actions... Request RequestCurrent = _tracker.GetRequestWithActions(startingInput.RequestId); IEnumerable<RequestAction> ActiveNotComplete = RequestCurrent.RequestActions.Where(x => (x.ActionTypeId == Common.Constants.AWSActivityTypeId || x.ActionTypeId == 2) && x.IsActive && !x.IsComplete); //if a request action was found that was "active" but not "complete" it must be run now if (ActiveNotComplete.Count() != 0) { //iterate through the active but not complete actions... foreach (RequestAction ra in ActiveNotComplete) { if (ra.ActionTypeId == 1) //if state completed... { //code to tell SWF to fire activity for the new state decisions.Add(CreateActivityDecision(startingInput, ra.RequestActionId ?? 0)); } if (ra.ActionTypeId == 2) //if timer { // setup the input for the activity task. Common.ActivityTaskCompletedResult state = new Common.ActivityTaskCompletedResult { StartingInput = startingInput, RequestActionId = ra.RequestActionId ?? 0 }; Decision decision = new Decision() { DecisionType = DecisionType.StartTimer, StartTimerDecisionAttributes = new StartTimerDecisionAttributes() { Control = Common.Utils.SerializeToJSON<Common.ActivityTaskCompletedResult>(state), StartToFireTimeout = "3", TimerId = DateTime.Now.Ticks.ToString() } }; decisions.Add(decision); } } } else { Console.WriteLine("Workflow execution complete for " + startingInput.RequestId); //code to tell SWF to complete workflow execution decisions.Add(CreateCompleteWorkflowExecutionDecision(activityStates)); } return decisions; }
List<Decision> Decide(DecisionTask task) { try { List<Decision> decisions = new List<Decision>(); var startEvent = task.Events.FirstOrDefault(x => x.EventType == EventType.WorkflowExecutionStarted); if (startEvent != null) { var pollId = startEvent.WorkflowExecutionStartedEventAttributes.Input; Logger.LogMessage("Processing decision task for poll id: " + pollId); var poll = PollProcessor.Instance.GetPollAsync(pollId).Result; if (poll != null) { if (poll.State == PollDefinition.POLL_STATE_UNSCHEDULE && DateTime.Now < poll.StartTime) { // Add second to compensate for the rounding var timeDelay = (int)(new TimeSpan(poll.StartTime.Ticks - DateTime.Now.Ticks).TotalSeconds) + 1; var decision = new Decision { DecisionType = DecisionType.StartTimer, StartTimerDecisionAttributes = new StartTimerDecisionAttributes { StartToFireTimeout = timeDelay.ToString(), TimerId = Guid.NewGuid().ToString() } }; decisions.Add(decision); PollProcessor.Instance.UpdatePollStateAsync(pollId, PollDefinition.POLL_STATE_SCHEDULE).Wait(); Logger.LogMessage("Scheduled timer for {0} seconds till activating poll.", timeDelay); } else if (poll.State == PollDefinition.POLL_STATE_SCHEDULE) { Decision decision = new Decision() { DecisionType = DecisionType.ScheduleActivityTask, ScheduleActivityTaskDecisionAttributes = new ScheduleActivityTaskDecisionAttributes() { ActivityType = new ActivityType() { Name = Constants.SWF_ACTIVTY_START_TIMER_EXPIRED, Version = Constants.SWF_ACTIVTY_START_TIMER_EXPIRED_VERSION }, TaskList = new TaskList { Name = Constants.SWF_ACTIVTY_START_TIMER_EXPIRED_TASKLIST }, HeartbeatTimeout = Constants.SWF_TIMEOUT, ScheduleToCloseTimeout = Constants.SWF_TIMEOUT, ScheduleToStartTimeout = Constants.SWF_TIMEOUT, StartToCloseTimeout = Constants.SWF_TIMEOUT, ActivityId = string.Format("{0}:{1}", Constants.SWF_ACTIVTY_START_TIMER_EXPIRED, DateTime.Now.Ticks), Input = poll.Id } }; decisions.Add(decision); Logger.LogMessage("Start timer complete now deciding to run the {0} activity to activate poll.", Constants.SWF_ACTIVTY_START_TIMER_EXPIRED); } else if (poll.State == PollDefinition.POLL_STATE_ACTIVE && DateTime.Now < poll.EndTime) { // Add second to compensate for the rounding var timeDelay = (int)(new TimeSpan(poll.EndTime.Ticks - DateTime.Now.Ticks).TotalSeconds) + 1; var decision = new Decision { DecisionType = DecisionType.StartTimer, StartTimerDecisionAttributes = new StartTimerDecisionAttributes { StartToFireTimeout = timeDelay.ToString(), TimerId = Guid.NewGuid().ToString() } }; decisions.Add(decision); Logger.LogMessage("Scheduled timer for {0} seconds till poll expires.", timeDelay); } else if (poll.State == PollDefinition.POLL_STATE_ACTIVE) { Decision decision = new Decision() { DecisionType = DecisionType.ScheduleActivityTask, ScheduleActivityTaskDecisionAttributes = new ScheduleActivityTaskDecisionAttributes() { ActivityType = new ActivityType() { Name = Constants.SWF_ACTIVTY_END_TIMER_EXPIRED, Version = Constants.SWF_ACTIVTY_END_TIMER_EXPIRED_VERSION }, TaskList = new TaskList { Name = Constants.SWF_ACTIVTY_END_TIMER_EXPIRED_TASKLIST }, HeartbeatTimeout = Constants.SWF_TIMEOUT, ScheduleToCloseTimeout = Constants.SWF_TIMEOUT, ScheduleToStartTimeout = Constants.SWF_TIMEOUT, StartToCloseTimeout = Constants.SWF_TIMEOUT, ActivityId = string.Format("{0}:{1}", Constants.SWF_ACTIVTY_END_TIMER_EXPIRED, DateTime.Now.Ticks), Input = poll.Id } }; decisions.Add(decision); Logger.LogMessage("End timer complete now deciding to run the {0} activity to expire poll.", Constants.SWF_ACTIVTY_END_TIMER_EXPIRED); } } } if (decisions.Count == 0) { Decision decision = new Decision() { DecisionType = DecisionType.CompleteWorkflowExecution, CompleteWorkflowExecutionDecisionAttributes = new CompleteWorkflowExecutionDecisionAttributes { } }; decisions.Add(decision); Logger.LogMessage("Workflow execution complete for {0}", task.WorkflowExecution.WorkflowId); } return decisions; } catch(Exception e) { string message = string.Format("Error processing work flow execution {0} and is being aborted: {1}\n", task.WorkflowExecution.WorkflowId, e.Message, e.StackTrace); Logger.LogMessage(message); Decision decision = new Decision() { DecisionType = DecisionType.CompleteWorkflowExecution, CompleteWorkflowExecutionDecisionAttributes = new CompleteWorkflowExecutionDecisionAttributes { Result = message } }; return new List<Decision> { decision }; } }