Amazon Simple Workflow Service
Developer Guide (API Version 2012-01-25)
« PreviousNext »
View the PDF for this guide.Go to the AWS Discussion Forum for this product.Go to the Kindle Store to download this guide in Kindle format.Did this page help you?  Yes | No |  Tell us about it...

Using Advanced Workflow Features in Amazon SWF

Implementing Exclusive Choice

In some scenarios, you might want to schedule a different set of activities based on the outcome of a previous activity. The exclusive choice pattern enables you to create flexible workflows that meet the complex requirements of your application.

The Amazon Simple Workflow Service (Amazon SWF) does not have a specific exclusive choice action. To use exclusive choice, you simply write your decider logic to make different decisions based on the results of the previous activity. Some applications for exclusive choice include the following:

  • Performing cleanup activities if the results of a previous activity were unsuccessful

  • Scheduling different activities based on whether the customer purchased a basic or advanced plan

  • Performing different customer authentication activities based on the customer's ordering history

In the e-commerce example, you might use exclusive choice to either ship or cancel an order based on the outcome of charging the credit card. In the following figure, the decider schedules the Ship Order and Record Completion activity tasks if the credit card is successfully charged. Otherwise, it schedules the Cancel Order and Email Customer activity tasks.

Diagram of customer order workflow

The decider schedules the ShipOrder activity if the credit card is successfully charged. Otherwise, the decider schedules the CancelOrder activity.

In this case, program the decider to interpret the history and determine whether the credit card was successfully charged. To do this, you might have logic similar to the following

IF lastEvent = "WorkflowExecutionStarted" 
	addToDecisions ScheduleActivityTask(ActivityType = "VerifyOrderActivity")

ELSIF lastEvent = "ActivityTaskCompleted" 
	    AND ActivityType = "VerifyOrderActivity" 
	addToDecisions ScheduleActivityTask(ActivityType = "ChargeCreditCardActivity")

#Successful Credit Card Charge Activities
ELSIF lastEvent = "ActivityTaskCompleted" 
      AND ActivityType = "ChargeCreditCardActivity"
  addToDecisions ScheduleActivityTask(ActivityType = "ShipOrderActivity")

ELSIF lastEvent = "ActivityTaskCompleted" 
	    AND ActivityType = "ShipOrderActivity" 
  addToDecisions ScheduleActivityTask(ActivityType = "RecordOrderCompletionActivity")

ELSIF lastEvent = "ActivityTaskCompleted" 
	    AND ActivityType = "RecordOrderCompletionActivity" 
	addToDecisions CompleteWorkflowExecution

#Unsuccessful Credit Card Charge Activities
ELSIF lastEvent = "ActivityTaskFailed" 
      AND ActivityType = "ChargeCreditCardActivity"
  addToDecisions ScheduleActivityTask(ActivityType = "CancelOrderActivity")

ELSIF lastEvent = "ActivityTaskCompleted" 
	    AND ActivityType = "CancelOrderActivity" 
	addToDecisions ScheduleActivityTask(ActivityType = "EmailCustomerActivity")

ELSIF lastEvent = "ActivityTaskCompleted" 
	    AND ActivityType = "EmailCustomerActivity" 
	addToDecisions CompleteWorkflowExecution

ENDIF

If the credit card was successfully charged, the decider should respond with RespondDecisionTaskCompleted to schedule the ShipOrder activity.

https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "taskToken": "12342e17-80f6-FAKE-TASK-TOKEN32f0223",
  "decisions":[
      {
          "decisionType":"ScheduleActivityTask",
          "scheduleActivityTaskDecisionAttributes":{
              "control":"OPTIONAL_DATA_FOR_DECIDER",
              "activityType":{
                  "name":"ShipOrder",
                  "version":"2.4"
              },
              "activityId":"3e2e6e55-e7c4-fee-deed-aa815722b7be",
              "scheduleToCloseTimeout":"3600",
              "taskList":{
                  "name":"SHIPPING"
              },
              "scheduleToStartTimeout":"600",
              "startToCloseTimeout":"3600",
              "heartbeatTimeout":"300",
              "input": "123 Main Street, Anytown, United States"
          }
      }
  ]
}

If the credit card was not successfully charged, the decider should respond with RespondDecisionTaskCompleted to schedule the CancelOrder activity.

https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "taskToken": "12342e17-80f6-FAKE-TASK-TOKEN32f0223",
  "decisions":[
      {
          "decisionType":"ScheduleActivityTask",
          "scheduleActivityTaskDecisionAttributes":{
              "control":"OPTIONAL_DATA_FOR_DECIDER",
              "activityType":{
                  "name":"CancelOrder",
                  "version":"2.4"
              },
              "activityId":"3e2e6e55-e7c4-fee-deed-aa815722b7be",
              "scheduleToCloseTimeout":"3600",
              "taskList":{
                  "name":"CANCELLATIONS"
              },
              "scheduleToStartTimeout":"600",
              "startToCloseTimeout":"3600",
              "heartbeatTimeout":"300",
              "input": "Out of Stock"
          }
      }
  ]
}

If Amazon SWF is able to validate the data in the RespondDecisionTaskCompleted action, Amazon SWF returns a successful HTTP response similar to the following.

HTTP/1.1 200 OK
Content-Length: 11
Content-Type: application/json
x-amzn-RequestId: 93cec6f7-0747-11e1-b533-79b402604df1

Timers

A timer enables you to notify your decider when a certain amount of time has elapsed. When responding to a decision task, the decider has the option to respond with a StartTimer decision. This decision specifies an amount of time after which the timer should fire. After the specified time has elapsed, Amazon SWF will add a TimerFired event to the workflow execution history and schedule a decision task. The decider can then use this information to inform further decisions. One common application for a timer is to delay the execution of an activity task. For example, a customer might want to take delayed delivery of an item.

Signals

Signals enable you to inform a workflow execution of external events and inject information into a workflow execution while it is running. Any program can send a signal to a running workflow execution by calling the SignalWorkflowExecution API. When a signal is received, Amazon SWF records it in the workflow execution's history as WorkflowExecutionSignaled event and alerts the decider by scheduling a decision task.

Note

An attempt to send a signal to a workflow execution that is not open results in SignalWorkflowExecution failing with UnknownResourceFault.

In this example, the workflow execution is sent a signal to cancel an order.

https://swf.us-east-1.amazonaws.com
SignalWorkflowExecution
{"domain": "867530901",
 "workflowId": "20110927-T-1",
 "runId": "f5ebbac6-941c-4342-ad69-dfd2f8be6689",
 "signalName": "CancelOrder",
 "input": "order 3553"}

If the workflow execution receives the signal, Amazon SWF returns a successful HTTP response similar to the following. Amazon SWF will generate a decision task to inform the decider to process the signal.

HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/json
x-amzn-RequestId: bf78ae15-3f0c-11e1-9914-a356b6ea8bdf

Sometimes you might want to wait for a signal. For example, a user could cancel an order by sending a signal, but only within one hour of placing the order. Amazon SWF does not have a primitive to enable a decider to wait for a signal from the service. Pause functionality needs to be implemented in the decider itself. In order to pause, the decider should start a timer, using the StartTimer decision, which specifies the duration for which the decider will wait for the signal while continuing to poll for decision tasks. When the decider receives a decision task, it should check the history to see if either the signal has been received or the timer has fired. If the signal has been received, then the decider should cancel the timer. However, if instead, the timer has fired, then it means that the signal did not arrive within the specified time. To summarize, in order to wait for a specific signal, do the following.

  1. Create a timer for the amount of time the decider should wait.

  2. When a decision task is received, check the history to see if the signal has arrived or if the timer has fired.

  3. If a signal has arrived, cancel the timer using a CancelTimer decision and process the signal. Depending on the timing, the history may contain both TimerFired and WorkflowExecutionSignaled events. In such cases, you can rely on the relative order of the the events in the history to determine which occurred first.

  4. If the timer has fired, before a signal is received, then the decider has timed out waiting for the signal. You can fail the execution or do whatever other logic is appropriate to your use case.

Activity Task Cancellation

Activity task cancellation enables the decider to end activities that no longer need to be performed. Amazon SWF uses a cooperative cancellation mechanism and does not forcibly interrupt running activity tasks. You must program your activity workers to handle cancellation requests.

The decider can decide to cancel an activity task while it is processing a decision task. To cancel an activity task, the decider uses the RespondDecisionTaskCompleted action with the RequestCancelActivityTask decision.

If the activity task has not yet been acquired by an activity worker, the service will cancel the task. Note that there is a potential race condition in that an activity worker could acquire the task at any time. If the task has already been assigned to an activity worker, then the activity worker will be requested to cancel the task.

In this example, the workflow execution is sent a signal to cancel the order.

https://swf.us-east-1.amazonaws.com
SignalWorkflowExecution
{"domain": "867530901",
 "workflowId": "20110927-T-1",
 "runId": "9ba33198-4b18-4792-9c15-7181fb3a8852",
 "signalName": "CancelOrder",
 "input": "order 3553"}

If the workflow execution receives the signal, Amazon SWF returns a successful HTTP response similar to the following. Amazon SWF will generate a decision task to inform the decider to process the signal.

HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/json
x-amzn-RequestId: 6c0373ce-074c-11e1-9083-8318c48dee96

When the decider processes the decision task and sees the signal in the history, the decider attempts to cancel the outstanding activity that has the ShipOrderActivity0001 activity ID. The activity ID is provided in the workflow history from the schedule activity task event.

https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "taskToken":"12342e17-80f6-FAKE-TASK-TOKEN32f0223",
  "decisions":[{
          "decisionType":"RequestCancelActivityTask",
          "RequestCancelActivityTaskDecisionAttributes":{
              "ActivityID":"ShipOrderActivity0001"
          }
      }
  ]
}

If Amazon SWF successfully receives the cancellation request, it returns a successful HTTP response similar to the following:

HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/json
x-amzn-RequestId: 6c0373ce-074c-11e1-9083-8318c48dee96

The cancellation attempt is recorded in the history as the ActivityTaskCancelRequested event.

If the task is successfully canceled—as indicated by an ActivityTaskCanceled event—program your decider to take the appropriate steps that should follow task cancellation such as closing the workflow execution.

If the activity task could not be canceled—for example, if the task completes, fails, or times out instead of canceling—your decider should accept the results of the activity or perform any cleanup or mitigation necessitated by your use case.

If the activity task has already been acquired by an activity worker, then the request to cancel is transmitted through the task-heartbeat mechanism. Activity workers can periodically use RecordActivityTaskHeartbeat to report to Amazon SWF that the task is still in progress.

Note that activity workers are not required to heartbeat, although it is recommended for long-running tasks. Task cancellation requires periodic heartbeat to be recorded; if the worker does not heartbeat, the task cannot be canceled.

If the decider requests a cancellation of the task, Amazon SWF sets the value of the cancelRequest object to true. The cancelRequest object is part of the ActivityTaskStatus object which is returned by the service in response to RecordActivityTaskHeartbeat.

Amazon SWF does not prevent the successful completion of an activity task whose cancellation has been requested; it is up to the activity to determine how to handle the cancellation request. Depending on your requirements, program the activity worker to either cancel the activity task or ignore the cancellation request.

If you want the activity worker to indicate that the work for the activity task was canceled, program it to respond with a RespondActivityTaskCanceled. If you want the activity worker to complete the task, program it to respond with a standard RespondActivityTaskCompleted.

When Amazon SWF receives the RespondActivityTaskCompleted or RespondActivityTaskCanceled request, it updates the workflow execution history and schedules a decision task to inform the decider.

Program the decider to process the decision task and return any additional decisions. If the activity task is successfully canceled, program the decider to perform the tasks needed to continue or close the workflow execution. If the activity task is not successfully canceled, program the decider to accept the results, ignore the results, or schedule any required cleanup.

Markers

You can use markers to record events in the workflow execution history for application specific purposes. Markers are useful when you want to record custom information to help implement decider logic. For example, you could use a marker to count the number of loops in a recursive workflow.

In the following example, the decider completes a decision task and responds with a RespondDecisionTaskCompleted action that contains a RecordMarker decision.

https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "taskToken":"12342e17-80f6-FAKE-TASK-TOKEN32f0223",
  "decisions":[{
          "decisionType":"RecordMarker",
          "recordMarkerDecisionAttributes":{
              "markerName":"customer elected special shipping offer"
          }
      },
  ]
}

If Amazon SWF successfully records the marker, it returns a successful HTTP response similar to the following.

HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/json
x-amzn-RequestId: 6c0373ce-074c-11e1-9083-8318c48dee96

Recording a marker does not, by itself, initiate a decision task. To prevent the workflow execution from becoming stuck, something must occur that continues the execution of the workflow. For example, this might include the decider scheduling another activity task, the workflow execution receiving a signal, or a previously scheduled activity task completing.

Tagging

As described in the section Tags, you can associate up to five tags with a workflow execution when you start the execution using the StartWorkflowExecution action, StartChildWorkflowExecution decision, or ContinueAsNewWorkflowExecution decision. Tagging enables you to filter your results when you use visibility actions to list or count workflow executions.

To use tagging

  1. Devise a tagging strategy. Think about your business requirements and create a list of tags that are meaningful to you. Determine which executions will get which tags. Even though an execution can be assigned a maximum of five tags, your tag library can have any number of tags. Because each tag can be any string value up to 256 characters in length, a tag can describe almost any business concept.

  2. Tag an execution with up to five tags when you create it.

  3. List or count the executions that are tagged with a particular tag by specifying the tagFilter parameter with the ListOpenWorkflowExecutions, ListClosedWorkflowExecutions, CountOpenWorkflowExecutions, and CountClosedWorkflowExecutions actions. The action will filter the executions based on the tags specified.

When you associate a tag with a workflow execution, it is permanently associated with that execution, and cannot be removed.

You can specify only one tag in the tagFilter parameter with ListWorkflowExecutions. Also, tag matching is case sensitive, and only exact matches return results.

Assume you have already set up two executions that are tagged as follows.

Execution NameAssigned Tags

Execution-One

Consumer, 2011-February

Execution-Two

Wholesale, 2011-March

You can filter the list of executions returned by ListOpenWorkflowExecutions on the Consumer tag. The oldestDate and latestDate values are specified as Unix Time values.

https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "domain":"867530901",
  "startTimeFilter":{
      "oldestDate":1262332800,
      "latestDate":1325348400
  },
  "tagFilter":{
    "tag":"Consumer"
    }
}