Implementing Activities

All activities in that are run with Amazon SWF use a registered activity type to identify the activity and set its default options. You can have the AWS Flow Framework for Ruby register the activity for you, or you can do this yourself. Either way, the primary attribute of any activity is the code that is run when the activity is run.

An Activity Implementation is a Ruby Method#

In Hello World, an activity was defined simply by creating an enclosing class and defining an activity method:

class HelloWorld
  def hello(input)
    "Hello #{input[:name]}!"
  end
end

The activity takes an input parameter that can receive data supplied to it by Amazon SWF when the activity is run.

Activities that are implemented this way are ideal if you're running a single activity with a default decider and default activity type. For more control over your activity type registration and to set activity options, you should base your activities classes on the Activities class, such as this set of activities from the Booking sample:

# BookingActivity class defines a set of activities for the Booking sample.
class BookingActivity
  extend AWS::Flow::Activities

  # The activity method is used to define activities. It accepts a list of names
  # of activities and a block specifying registration options for those
  # activities
  activity :reserve_car, :reserve_air, :send_confirmation do
    {
      version: "1.0",
    }
  end

  # This activity can be used to reserve a car for a given request_id
  def reserve_car(request_id)
    puts "Reserving car for Request ID: #{request_id}\n"
  end

  # This activity can be used to reserve a flight for a given request_id
  def reserve_air(request_id)
    puts "Reserving airline for Request ID: #{request_id}\n"
  end

  # This activity can be used to send a booking confirmation to the customer
  def send_confirmation(customer_id)
    puts "Sending notification to customer: #{customer_id}\n"
  end
end

This class defines three activities and sets the same activity registration options for each. In your own Activities-based classes, you can use this technique to set the same options for multiple activity methods, or you can provide separate options for each activity.

Activity Registration#

Amazon SWF must know about your activity type in order to process tasks for it; registering an activity type provides the activity's name, version, and default options to Amazon SWF so that the activity can be referenced and run in your workflows.

Activities that you define using the AWS Flow Framework for Ruby are automatically registered by the framework when necessary. Activities that have already been registered are used when they are referenced in your code, and any activities that are not yet registered will be registered for you by the framework when your code is run for the first time.

When the AWS Flow Framework for Ruby registers an activity type for you, its name is taken to be a combination of the activity's class and method names. For example, the reserve_car method defined in the Booking example's BookingActivities class will be named BookingActivities.reserve_car in your workflow history.

Whether you define one or not, version of an activity is required by Amazon SWF, and is either automatically assigned by the framework (in the case that you define an activity to run as in the Hello World sample) or can be set using an the version registration option when the activity is declared in your Activities-based class, as with the Booking sample. When an activity version is automatically applied, the default value of 1.0 is used. Activity versions are not restricted to numeric values: "1.0", "1.2a", and "version_three" are all valid version fields.

Like all Amazon SWF types, activity types are scoped to a particular domain, AWS account, and region. Activities that are registered in other domains, regions, or to another account are unrelated, even if they share the same name, version or other options.

Within a domain, region and account, an activity type is uniquely identified by the combination of its name and version. Once registered, an activity type is immutable: Any changes you make to an activity's default options must be accompanied by either a change to its name, its version, or both.

Scheduling and Running Activities#

Activities are scheduled to be run within your workflow implementation, also known as your workflow's decider logic. The AWS Flow Framework for Ruby provides a default decider that can run a single activity that you provide to the start method:

require 'aws/decider'
AWS::Flow::start("HelloWorld.hello", { name: "AWS Flow Framework!" })

When working with multi-step workflows, you will often want to write the decider logic yourself. The Booking sample implements a synchronization-pattern workflow by scheduling two activities asynchronously, and then waiting for all of the futures to be set before completing the workflow:

require 'flow/activities'

# BookingWorkflow class defines the workflows for the Booking sample
class BookingWorkflow
  extend AWS::Flow::Workflows

  # Use the workflow method to define workflow entry point.
  workflow :make_booking do
    {
      version: "1.0",
      default_execution_start_to_close_timeout: 120
    }
  end

  # Create an activity client using the activity_client method to schedule
  # activities
  activity_client(:client) { { from_class: "BookingActivity" } }

  # This is the entry point for the workflow
  def make_booking options

    puts "Workflow has started\n" unless is_replaying?
    # This array will hold all futures that are created when asynchronous
    # activities are scheduled
    futures = []

    if options[:reserve_car]
      puts "Reserving a car for customer\n" unless is_replaying?
      # The activity client can be used to schedule activities
      # asynchronously by using the send_async method
      futures << client.send_async(:reserve_car, options[:request_id])
    end
    if options[:reserve_air]
      puts "Reserving air ticket\n" unless is_replaying?
      futures << client.send_async(:reserve_air, options[:customer_id])
    end

    puts "Waiting for reservation to complete\n" unless is_replaying?
    # wait_for_all is a flow construct that will wait on the array of
    # futures passed to it
    wait_for_all(futures)

    # After waiting on the reservation activities to complete, the workflow
    # will call the send_confirmation activity.
    client.send_confirmation(options[:customer_id])

    puts "Workflow has completed\n" unless is_replaying?
  end

  # Helper method to check if Flow is replaying the workflow. This is used to
  # avoid duplicate log messages
  def is_replaying?
    decision_context.workflow_clock.replaying
  end
end

Note

For more information about implementing workflow patterns and about writing asynchronous workflows, see the topics Implementing Workflow Patterns and Executing Tasks Asynchronously, respectively.

Activities are run when an activity worker that is polling for activity tasks receives an activity task event from Amazon SWF for a particular activity, runs the activity and then reports the result back to Amazon SWF.

You can code activity workers yourself, or you can use the aws-flow-ruby utility to spawn workers that will automatically run activities for you. Information about how to use each method is provided in the linked topics.

For More Information#

More information and further examples of activity implementation, registration and scheduling, refer to the following topics and resources:

  • Specifying Workflow and Activity Options – Provides information about setting activity options during registration or when scheduling an activity.
  • Amazon SWF Timeout Types – Provides information about timeouts for activities and what they mean in the context of the activity's life-cycle.
  • Implementing Workflow Patterns – Provides information about how to design your decider code to replicate many common workflow patterns.
  • Setting Task Priority – Provides information about how to set a task priority value to your activities to affect which activity tasks are delivered to your workers first.
  • aws-flow-ruby – Provides information about how to set up and spawn workers for your activities and workflows with a simple configuration file and the aws-flow-ruby utility.
  • awslabs/aws-flow-ruby-samples – A GitHub repository with examples and recipes that provide code examples of activity and workflow implementations using the AWS Flow Framework for Ruby.