

# Tutorials and workshops for learning Step Functions
<a name="learning-resources"></a>

Learn from this guide, workshops, and practical tutorials how to integrate and orchestrate services with Step Functions.

![\[Visual examples of six common workflow use cases, noted in the following workshops and tutorials.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/use-case-examples.png)


## Tutorials for learning Step Functions
<a name="tutorials"></a>

For a quick introduction, see: [Getting started tutorial](getting-started.md).

For specific scenarios, see the following tutorials:
+ [Handling error conditions in a Step Functions state machine](tutorial-handling-error-conditions.md)
+ [Create a Step Functions state machine using AWS SAM](tutorial-state-machine-using-sam.md)
+ [Using CloudFormation to create a workflow in Step Functions](tutorial-lambda-state-machine-cloudformation.md)
+ [Using AWS CDK to create an Express workflow in Step Functions](tutorial-step-functions-rest-api-integration-cdk.md)
+ [Using AWS CDK to create a Standard workflow in Step Functions](tutorial-lambda-state-machine-cdk.md)
+ [Examining state machine executions in Step Functions](debug-sm-exec-using-ui.md)
+ [Creating a Step Functions state machine that uses Lambda](tutorial-creating-lambda-state-machine.md)
+ [Deploying a workflow that waits for human approval in Step Functions](tutorial-human-approval.md)
+ [Using Inline Map state to repeat an action in Step Functions](tutorial-map-inline.md)
+ [Copying large-scale CSV data using Distributed Map in Step Functions](tutorial-map-distributed.md)
+ [Iterate a loop with a Lambda function in Step Functions](tutorial-create-iterate-pattern-section.md)
+ [Processing batch data with a Lambda function in Step Functions](tutorial-itembatcher-param-task.md)
+ [Processing individual items with a Lambda function in Step Functions](tutorial-itembatcher-single-item-process.md)
+ [Starting a Step Functions workflow in response to events](tutorial-cloudwatch-events-s3.md)
+ [Creating a Step Functions API using API Gateway](tutorial-api-gateway.md)
+ [Creating an Activity state machine using Step Functions](tutorial-creating-activity-state-machine.md)
+ [View X-Ray traces in Step Functions](tutorial-xray-traces.md)
+ [Gather Amazon S3 bucket info using AWS SDK service integrations](tutorial-gather-s3-info.md)
+ [Continue long-running workflows using Step Functions API (recommended)](tutorial-continue-new.md)
+ [Using a Lambda function to continue a new execution in Step Functions](tutorial-use-lambda-cont-exec.md)
+ [Accessing cross-account AWS resources in Step Functions](tutorial-access-cross-acct-resources.md)

**Learn with starter templates**  
To deploy and learn from ready-to-run state machines for a variety of use cases, see [Starter templates](starter-templates.md).

# Handling error conditions in a Step Functions state machine
<a name="tutorial-handling-error-conditions"></a>

In this tutorial, you create an AWS Step Functions state machine with a **Task** state that invokes an example Lambda function built to throw a custom error.

Tasks are one of the [Fallback states](concepts-error-handling.md#error-handling-fallback-states), for which you can configure a `Catch` field. When errors are received by the integration, next steps are chosen by the catch field based on the error name.

## Step 1: Create a Lambda function that throws an error
<a name="create-lambda-function-fail"></a>

Use a Lambda function to simulate an error condition.

1. Open the AWS Lambda console at [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/).

1. Choose **Create function**.

1. Choose **Use a blueprint**, search for `Step Functions`, and choose **Throw a custom error**.

1. For **Function name**, enter `ThrowErrorFunction`.

1. For **Role**, choose **Create a new role with basic Lambda permissions**.

1. Choose **Create function**.

   The following code should be displayed in the **code** pane.

   ```
   export const handler = async () => {
       function CustomError(message) {
           this.name = 'CustomError';
           this.message = message;
       }
       CustomError.prototype = new Error();
   
       throw new CustomError('This is a custom error!');
   };
   ```

## Step 2: Test your Lambda function
<a name="error-conditions-test"></a>

Before creating a state machine, verify your Lambda function throws your `CustomError` when invoked.

1. Choose the **Test** tab.

1. Choose **Create a new event** and keep the default **Event JSON**

1. Choose **Test** to invoke your function with your test event.

1. Expand **Executing function** to review the details of the thrown error.

You now have a Lambda function ready to throw a custom error.

In the next step, you will set up a state machine to catch and retry on that error.

## Step 3: Create your state machine machine
<a name="state-machine-create-step"></a>

Use the Step Functions console to create a state machine that uses a [Task workflow state](state-task.md) with a `Catch` configuration. The state machine will invoke the Lambda function, which you've built to simulate throwing an error when the function is invoked. Step Functions retries the function using exponential backoff between retries.

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.

1. Choose **Create from blank**, and for **State machine name**, enter *CatchErrorStateMachine*.

1. Accept the default type (Standard), then choose **Continue** to edit your state machine in Workflow Studio.

1. Choose **Code** to switch to the ASL editor, then replace the code with following state machine definition:

   ```
   {
     "Comment": "Example state machine that can catch a custom error thrown by a function integration.",
     "StartAt": "CreateAccount",
     "States": {
       "CreateAccount": {
         "Type": "Task",
         "Resource": "arn:aws:states:::lambda:invoke",
         "Output": "{% $states.result.Payload %}",
         "Arguments": {
           "FunctionName": "arn:aws:lambda:region:account-id:function:ThrowErrorFunction:$LATEST",
           "Payload": "{% $states.input %}"
         },
         "Catch": [
           {
             "ErrorEquals": [
               "CustomError"
             ],
             "Next": "CustomErrorFallback"
           },
           {
             "ErrorEquals": [
               "States.ALL"
             ],
             "Next": "CatchAllFallback"
           }
         ],
         "End": true,
         "Retry": [
           {
             "ErrorEquals": [
               "CustomError",
               "Lambda.ServiceException",
               "Lambda.AWSLambdaException",
               "Lambda.SdkClientException",
               "Lambda.TooManyRequestsException"
             ],
             "IntervalSeconds": 1,
             "MaxAttempts": 3,
             "BackoffRate": 2,
             "JitterStrategy": "FULL"
           }
         ]
       },
       "CustomErrorFallback": {
         "Type": "Pass",
         "End": true,
         "Output": {
           "Result": "Fallback from a custom error function."
         }
       },
       "CatchAllFallback": {
         "Type": "Pass",
         "End": true,
         "Output": {
           "Result": "Fallback from all other error codes."
         }
       }
     },
     "QueryLanguage": "JSONata"
   }
   ```

## Step 4: Configure your state machine
<a name="state-machine-configure"></a>

Before you run your state machine, you must first connect to the Lambda function that you previously created.

1. Switch back to **Design** mode and select the **Lambda : Invoke** task state named **CreateAccount**. 

1. On the **Configuration** tab, look for **API Arguments**. For **Function name** choose the Lambda function that you created earlier.

1. Choose **Create**, review the roles, then choose **Confirm** to create your state machine.

## Step 5: Run the state machine
<a name="error-conditions-execution"></a>

After you create and configure your state machine, you can run it and examine the flow.

1. In the editor, choose **Execute**.

   Alternatively, from the **State machines** list, choose **Start execution**.

1. In the **Start execution** dialog box, accept the generated ID, and for **Input**, enter the following JSON:

   ```
   { "Cause" : "Custom Function Error" }
   ```

1. Choose **Start execution**.

The Step Functions console directs you to a page that's titled with your execution ID, known as the *Execution Details* page. You can review the execution results as the workflow progresses and after it completes.

To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

Your state machine invokes the Lambda function, which throws a `CustomError`. Choose the **CreateAccount** step in the **Graph view** to see the state output. Your state machine output should look similar to the following illustration: 

![\[Illustrative screenshot of the workflow catching the custom error.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-console-retry-state-machine-error-output.png)


**Congratulations\$1**

 You now have a state machine that can catch and handle error conditions thrown by a Lambda function. You can use this pattern to implement robust error handling in your workflows.

**Note**  
You can also create state machines that [Retry](concepts-error-handling.md#error-handling-retrying-after-an-error) on timeouts or those that use `Catch` to transition to a specific state when an error or timeout occurs. For examples of these error handling techniques, see [Examples Using Retry and Using Catch](concepts-error-handling.md#error-handling-examples).

# Create a Step Functions state machine using AWS SAM
<a name="tutorial-state-machine-using-sam"></a>

In this guide, you download, build, and deploy a sample AWS SAM application that contains an AWS Step Functions state machine. This application creates a mock stock trading workflow which runs on a pre-defined schedule (note that the schedule is disabled by default to avoid incurring charges).

The following diagram shows the components of this application:

![\[Diagram showing the workflow for this tutorial.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/sam-starter-template-docs.png)


The following is a preview of commands that you run to create your sample application. For more details about each of these commands, see the sections later in this page

```
# Step 1 - Download a sample application. For this tutorial you
#   will follow the prompts to select an AWS Quick Start Template
#   called 'Multi-step workflow'
sam init

# Step 2 - Build your application
cd project-directory
sam build

# Step 3 - Deploy your application
sam deploy --guided
```

## Prerequisites
<a name="tutorial-state-machine-using-sam-prerequisites"></a>

This guide assumes that you've completed the steps in the [Installing the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) for your OS. It assumes that you've done the following:

1. Created an AWS account.

1. Configured IAM permissions.

1. Installed Homebrew. Note: Homebrew is only a prerequisite for Linux and macOS.

1. Installed the AWS SAM CLI. Note: Make sure you have version 0.52.0 or later. You can check which version you have by executing the command `sam --version`.

## Step 1: Download a Sample AWS SAM Application
<a name="tutorial-state-machine-using-sam-initialize"></a>

**Command to run:**

```
sam init
```

Follow the on-screen prompts to select the following:

1. **Template:** AWS Quick Start Templates

1. **Language:** Python, Ruby, NodeJS, Go, Java, or .NET

1. **Project name:** (name of your choice - default is `sam-app`)

1. **Quick start application:** Multi-step workflow

**What AWS SAM is doing:**

This command creates a directory with the name you provided for the 'Project name' prompt (default is `sam-app`). The specific contents of the directory will depend on the language you choose.

Following are the directory contents when you choose one of the Python runtimes:

```
├── README.md
├── functions
│   ├── __init__.py
│   ├── stock_buyer
│   │   ├── __init__.py
│   │   ├── app.py
│   │   └── requirements.txt
│   ├── stock_checker
│   │   ├── __init__.py
│   │   ├── app.py
│   │   └── requirements.txt
│   └── stock_seller
│       ├── __init__.py
│       ├── app.py
│       └── requirements.txt
├── statemachine
│   └── stock_trader.asl.json
├── template.yaml
└── tests
    └── unit
        ├── __init__.py
        ├── test_buyer.py
        ├── test_checker.py
        └── test_seller.py
```

There are two especially interesting files that you can take a look at:
+ `template.yaml`: Contains the AWS SAM template that defines your application's AWS resources.
+ `statemachine/stockTrader.asl.json`: Contains the application's state machine definition, which is written in [Using Amazon States Language to define Step Functions workflows](concepts-amazon-states-language.md).

You can see the following entry in the `template.yaml` file, which points to the state machine definition file:



```
    Properties:
      DefinitionUri: statemachine/stock_trader.asl.json
```

It can be helpful to keep the state machine definition as a separate file instead of embedding it in the AWS SAM template. For example, tracking changes to the state machine definition is easier if you don't include the definition in the template. You can use the Workflow Studio to create and maintain the state machine definition, and export the definition from the console directly to the Amazon States Language specification file without merging it into the template.

For more information about the sample application, see the `README.md` file in the project directory.

## Step 2: Build Your Application
<a name="tutorial-state-machine-using-sam-build"></a>

**Command to run:**

First change into the project directory (that is, the directory where the `template.yaml` file for the sample application is located; by default is `sam-app`), then run this command:

```
sam build
```

**Example output:**

```
  
 Build Succeeded

 Built Artifacts  : .aws-sam/build
 Built Template   : .aws-sam/build/template.yaml

 Commands you can use next
 =========================
 [*] Invoke Function: sam local invoke
 [*] Deploy: sam deploy --guided
```

**What AWS SAM is doing:**

The AWS SAM CLI comes with abstractions for a number of Lambda runtimes to build your dependencies, and copies all build artifacts into staging folders so that everything is ready to be packaged and deployed. The `sam build` command builds any dependencies that your application has, and copies the build artifacts to folders under `.aws-sam/build`.

## Step 3: Deploy Your Application to the AWS Cloud
<a name="tutorial-state-machine-using-sam-deploy"></a>

**Command to run:**

```
sam deploy --guided
```

Follow the on-screen prompts. You can just respond with `Enter` to accept the default options provided in the interactive experience.

**What AWS SAM is doing:**

This command deploys your application to the AWS cloud. It take the deployment artifacts you build with the `sam build` command, packages and uploads them to an Amazon S3 bucket created by AWS SAM CLI, and deploys the application using CloudFormation. In the output of the deploy command you can see the changes being made to your CloudFormation stack.

You can verify the example Step Functions state machine was successfully deployed by following these steps:

1. Sign in to the AWS Management Console and open the Step Functions console at [https://console.aws.amazon.com/states/](https://console.aws.amazon.com/states/).

1. In the left navigation, choose **State machines**.

1. Find and choose your new state machine in the list. It will be named StockTradingStateMachine-*<unique-hash>*.

1. Choose the **Definition** tab.

You should now see a visual representation of your state machine. You can verify that the visual representation matches the state machine definition found in the `statemachine/stockTrader.asl.json` file of your project directory.

## Troubleshooting
<a name="tutorial-state-machine-using-sam-troubleshooting"></a>

### SAM CLI error: "no such option: --guided"
<a name="tutorial-state-machine-using-sam-troubleshooting-guided"></a>

When executing `sam deploy`, you see the following error:

```
 
Error: no such option: --guided
```

This means that you are using an older version of the AWS SAM CLI that does not support the `--guided` parameter. To fix this, you can either update your version of AWS SAM CLI to 0.33.0 or later, or omit the `--guided` parameter from the `sam deploy` command.

### SAM CLI error: "Failed to create managed resources: Unable to locate credentials"
<a name="tutorial-state-machine-using-sam-troubleshooting-credentials"></a>

When executing `sam deploy`, you see the following error:

```
 
Error: Failed to create managed resources: Unable to locate credentials
```

This means that you have not set up AWS credentials to enable the AWS SAM CLI to make AWS service calls. To fix this, you must set up AWS credentials. For more information, see [Setting Up AWS Credentials](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started-set-up-credentials.html) in the *AWS Serverless Application Model Developer Guide*.

## Clean Up
<a name="tutorial-state-machine-using-sam-cleanup"></a>

If you no longer need the AWS resources you created by running this tutorial, you can remove them by deleting the CloudFormation stack that you deployed.

To delete the CloudFormation stack created with this tutorial using the AWS Management Console, follow these steps:

1. Sign in to the AWS Management Console and open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. In the left navigation pane, choose **Stacks**.

1. In the list of stacks, choose **sam-app** (or the name of stack you created).

1. Choose **Delete**.

When done, the status of the of the stack will change to **DELETE\$1COMPLETE**.

Alternatively, you can delete the CloudFormation stack by executing the following AWS CLI command:

```
aws cloudformation delete-stack --stack-name sam-app --region region
```

### Verify Deleted Stack
<a name="tutorial-state-machine-using-sam-cleanup-verify"></a>

For both methods of deleting the CloudFormation stack, you can verify it was deleted by going to the [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/), choosing **Stacks** in the left navigation pane, and choosing **Deleted** in the dropdown to the right of the search text box. You should see your stack name **sam-app** (or the name of the stack you created) in the list of deleted stacks.

# Examining state machine executions in Step Functions
<a name="debug-sm-exec-using-ui"></a>

In this tutorial, you will learn how to inspect the execution information displayed on the *Execution Details* page and view the reason for a failed execution. Then, you'll learn how to access different iterations of a `Map` state execution. Finally, you'll learn how to configure the columns on the **Table view** and apply suitable filters to view only the information of interest to you.

In this tutorial, you create a Standard type state machine, which obtains the price of a set of fruits. To do this, the state machine uses three AWS Lambda functions which return a random list of four fruits, the price of each fruit, and the average cost of the fruits. The Lambda functions are designed to throw an error if the price of the fruits is less than or equal to a threshold value.

**Note**  
While the following procedure contains instructions for how to examine the details of a Standard workflow execution, you can also examine the details for Express workflow executions. For information about the differences between the execution details for Standard and Express workflow types, see [Standard and Express console experience differences](concepts-view-execution-details.md#console-exp-differences).

## Step 1: Create and test the required Lambda functions
<a name="step-create-all-lambda-functions"></a>

1. Open the [Lambda console](https://console.aws.amazon.com/lambda/home) and then perform steps 1 through 4 in the [Step 1: Create a Lambda function](tutorial-creating-lambda-state-machine.md#create-lambda-function) section. Make sure to name the Lambda function **GetListOfFruits**.

1. After you create your Lambda function, copy the function's Amazon Resource Name (ARN) displayed in the upper-right corner of the page. To copy the ARN, click the copy icon to copy the Lambda function's Amazon Resource Name. The following is an example ARN, where *`function-name`* is the name of the Lambda function (in this case, `GetListOfFruits`):

   ```
   arn:aws:lambda:region:123456789012:function:function-name
   ```

1. Copy the following code for the Lambda function into the **Code source** area of the **GetListOfFruits** page.

   ```
   function getRandomSubarray(arr, size) {
       var shuffled = arr.slice(0), i = arr.length, temp, index;
       while (i--) {
           index = Math.floor((i + 1) * Math.random());
           temp = shuffled[index];
           shuffled[index] = shuffled[i];
           shuffled[i] = temp;
       }
       return shuffled.slice(0, size);
   }
   
   exports.handler = async function(event, context) {
       
       const fruits = ['Abiu','Açaí','Acerola','Ackee','African cucumber','Apple','Apricot','Avocado','Banana','Bilberry','Blackberry','Blackcurrant','Jostaberry'];
   
       
        const errorChance = 45;
       
       const waitTime = Math.floor( 100 * Math.random() );
   
       await new Promise( r => setTimeout(() => r(), waitTime));
   
       const num = Math.floor( 100 * Math.random() );
       // const num = 51;
        if (num <= errorChance) {
            throw(new Error('Error'));
        }
   
       return getRandomSubarray(fruits, 4);
   };
   ```

1. Choose **Deploy**, and then choose **Test**, to deploy the changes and see the output of your Lambda function.

1. Create two additional Lambda functions, named **GetFruitPrice** and **CalculateAverage** respectively, with the following steps:

   1. Copy the following code into the **Code source** area of the **GetFruitPrice** Lambda function:

      ```
      exports.handler = async function(event, context) {
          
          const errorChance = 0;
          const waitTime = Math.floor( 100 * Math.random() );
      
          await new Promise( r => setTimeout(() => r(), waitTime));
      
          const num = Math.floor( 100 * Math.random() );
          if (num <= errorChance) {
              throw(new Error('Error'));
          }
      
          return Math.floor(Math.random()*100)/10;
      };
      ```

   1. Copy the following code into the **Code source** area of the **CalculateAverage** Lambda function:

      ```
      function getRandomSubarray(arr, size) {
          var shuffled = arr.slice(0), i = arr.length, temp, index;
          while (i--) {
              index = Math.floor((i + 1) * Math.random());
              temp = shuffled[index];
              shuffled[index] = shuffled[i];
              shuffled[i] = temp;
          }
          return shuffled.slice(0, size);
      }
      
      const average = arr => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length;
          
      exports.handler = async function(event, context) {
              const errors = [
              "Error getting data from DynamoDB",
              "Error connecting to DynamoDB",
              "Network error",
              "MemoryError - Low memory"
              ]
              
          const errorChance = 0;
          
          const waitTime = Math.floor( 100 * Math.random() );
      
          await new Promise( r => setTimeout(() => r(), waitTime));
      
          const num = Math.floor( 100 * Math.random() );
          if (num <= errorChance) {
              throw(new Error(getRandomSubarray(errors, 1)[0]));
          }
      
          return average(event);
      };
      ```

   1. Make sure to copy the ARNs of these two Lambda functions, and then **Deploy** and **Test** them.

## Step 2: Create and execute the state machine
<a name="step-create-exec-sm"></a>

Use the [Step Functions console](https://console.aws.amazon.com/states/home?region=us-east-1#/) to create a state machine that invokes the [Lambda functions you created in Step 1](#step-create-all-lambda-functions). In this state machine, three `Map` states are defined. Each of these `Map` states contains a `Task` state that invokes one of your Lambda functions. Additionally, a `Retry` field is defined in each `Task` state with a number of retry attempts defined for each state. If a `Task` state encounters a runtime error, it's executed again up to the number of retry attempts defined for that `Task`.

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home) and choose **Write your workflow in code**.
**Important**  
Ensure that your state machine is under the same AWS account and Region as the Lambda function you created earlier.

1. For **Type**, keep the default selection of **Standard**.

1. Copy the following Amazon States Language definition and paste it under **Definition**. Make sure to replace the ARNs shown with those of the Lambda functions that you previously created.

   ```
   {
       "StartAt": "LoopOverStores",
       "States": {
           "LoopOverStores": {
               "Type": "Map",
               "Iterator": {
                   "StartAt": "GetListOfFruits",
                   "States": {
                       "GetListOfFruits": {
                           "Type": "Task",
                           "Resource": "arn:aws:states:::lambda:invoke",
                           "OutputPath": "$.Payload",
                           "Parameters": {
                               "FunctionName": "arn:aws:lambda:region:123456789012:function:GetListofFruits:$LATEST",
                               "Payload": {
                                   "storeName.$": "$"
                               }
                           },
                           "Retry": [
                               {
                                   "ErrorEquals": [
                                       "States.ALL"
                                   ],
                                   "IntervalSeconds": 2,
                                   "MaxAttempts": 1,
                                   "BackoffRate": 1.3
                               }
                           ],
                           "Next": "LoopOverFruits"
                       },
                       "LoopOverFruits": {
                           "Type": "Map",
                           "Iterator": {
                               "StartAt": "GetFruitPrice",
                               "States": {
                                   "GetFruitPrice": {
                                       "Type": "Task",
                                       "Resource": "arn:aws:states:::lambda:invoke",
                                       "OutputPath": "$.Payload",
                                       "Parameters": {
                                           "FunctionName": "arn:aws:lambda:region:123456789012:function:GetFruitPrice:$LATEST",
                                           "Payload": {
                                               "fruitName.$": "$"
                                           }
                                       },
                                       "Retry": [
                                           {
                                               "ErrorEquals": [
                                                   "States.ALL"
                                               ],
                                               "IntervalSeconds": 2,
                                               "MaxAttempts": 3,
                                               "BackoffRate": 1.3
                                           }
                                       ],
                                       "End": true
                                   }
                               }
                           },
                           "ItemsPath": "$",
                           "End": true
                       }
                   }
               },
               "ItemsPath": "$.stores",
               "Next": "LoopOverStoreFruitsPrice",
               "ResultPath": "$.storesFruitsPrice"
           },
           "LoopOverStoreFruitsPrice": {
               "Type": "Map",
               "End": true,
               "Iterator": {
                   "StartAt": "CalculateAverage",
                   "States": {
                       "CalculateAverage": {
                           "Type": "Task",
                           "Resource": "arn:aws:states:::lambda:invoke",
                           "OutputPath": "$.Payload",
                           "Parameters": {
                               "FunctionName": "arn:aws:lambda:region:123456789012:function:Calculate-average:$LATEST",
                               "Payload.$": "$"
                           },
                           "Retry": [
                               {
                                   "ErrorEquals": [
                                       "States.ALL"
                                   ],
                                   "IntervalSeconds": 2,
                                   "MaxAttempts": 2,
                                   "BackoffRate": 1.3
                               }
                           ],
                           "End": true
                       }
                   }
               },
               "ItemsPath": "$.storesFruitsPrice",
               "ResultPath": "$.storesPriceAverage",
               "MaxConcurrency": 1
           }
       }
   }
   ```

1. Enter a name for your state machine. Keep the default selections for the other options on this page and choose **Create state machine**.

1. Open the page titled with your state machine name. Perform steps 1 through 4 in the [Step 4: Run the state machine](tutorial-creating-lambda-state-machine.md#start-lambda-function) section, but use the following data as the execution input:

   ```
   {
       "stores": [
         "Store A",
         "Store B",
         "Store C",
         "Store D"
       ]
   }
   ```

## Step 3: View the state machine execution details
<a name="view-sm-exec-details"></a>

On the page titled with your execution ID, you can review the results of your execution and debug any errors.

1. (Optional) Choose from the tabs displayed on the *Execution Details* page to see the information present in each of them. For example, to view the state machine input and its execution output, choose **Execution input & output** on the *[Execution summary](concepts-view-execution-details.md#exec-details-intf-exec-summ)* section.

1. If your state machine execution failed, choose **Cause** or **Show step detail** on the error message. Details about the error are displayed in the *[Step details](concepts-view-execution-details.md#exec-details-intf-step-details)* section. Notice that the step that caused the error, which is a `Task` state named **GetListofFruits**, is highlighted in the **Graph view** and **Table view**.
**Note**  
Because the **GetListofFruits** step is defined inside a `Map` state, and the step failed to execute successfully, the **Status** of `Map` state step is displayed as **Failed**.

## Step 4: Explore the different *View modes*
<a name="sm-exec-details-exp-view-modes"></a>

You can choose a preferred mode to view either the state machine workflow or the execution event history. Some of the tasks that you can perform in these *View modes* are as follows:

### **Graph view** – Switch between different `Map` state iterations
<a name="graph-view-see-map-state-iterations"></a>

If your **Map** state has five iterations and you want to view the execution details for the third and fourth iterations, do the following:

1. Choose the `Map` state that you want to view the iteration data for.

1. From **Map iteration viewer**, choose the iteration that you want to view. Iterations are counted from zero. To choose the third iteration out of five, choose **\$12** from the dropdown list next to the **Map** state's name.
**Note**  
If your state machine contains nested `Map` states, Step Functions displays the parent and child `Map` state iterations as two separate dropdown lists representing the iteration data for the nested states.

1. (Optional) If one or more of your `Map` state iterations failed to execute or was stopped in an aborted state, you can view details about the failed iteration. To see these details, choose the affected iteration numbers under **Failed** or **Aborted** in the dropdown list.

### **Table view** – Switch between different `Map` state iterations
<a name="table-view-see-map-state-iterations"></a>

If your **Map** state has five iterations and you want to view the execution details for the iteration number three and four, do the following:

1. Choose the `Map` state for which you want to view the different iteration data.

1. In the tree view display of the `Map` state iterations, choose the row for iteration named **\$12** for iteration number three. Similarly, choose the row named **\$13** for iteration number four.

### **Table view** – Configure the columns to display
<a name="table-view-cfg-display-cols"></a>

Choose the settings icon. Then, in the **Preferences** dialog box, choose the columns you want to display under **Select visible columns**.

By default, this mode displays the **Name**, **Type**, **Status**, **Resource**, and **Started After** columns.

### **Table view** – Filter the results
<a name="table-view-filter-results"></a>

Limit the amount of information displayed by applying one or more filters based on a property, such as **Status**, or a date and time range. For example, to view the steps that failed execution, apply the following filter:

1. Choose **Filter by properties or search by keyword**, and then choose **Status** under **Properties**.

1. Under **Operators**, choose **Status =**.

1. Choose **Status = Failed**.

1. (Optional) Choose **Clear filters** to remove the applied filters.

### **Event view** – Filter the results
<a name="event-view-filter-results"></a>

Limit the amount of information displayed by applying one or more filters based on a property, such as **Type**, or a date and time range. For example, to view the `Task` state steps that failed execution, apply the following filter:

1. Choose **Filter by properties or search by keyword**, and then choose **Type** under **Properties**.

1. Under **Operators**, choose **Type =**.

1. Choose **Type = TaskFailed**.

1. (Optional) Choose **Clear filters** to remove the applied filters.

### **Event view** – Inspect a **TaskFailed** event detail
<a name="event-view-inspect-failed-task-details"></a>

Choose the arrow icon next to the ID of a **TaskFailed** event to inspect its details, including input, output, and resource invocation that appear in a dropdown box.

# Creating a Step Functions state machine that uses Lambda
<a name="tutorial-creating-lambda-state-machine"></a>

In this tutorial, you will create a single-step workflow using AWS Step Functions to invoke an AWS Lambda function.

**Note**  
Step Functions is based on *state machines* and *tasks*. In Step Functions, state machines are called *workflows*, which are a series of event-driven steps. Each step in a workflow is called a *state*. For example, a [Task state](state-task.md) represents a unit of work that another AWS service performs, such as calling another AWS service or API. Instances of running workflows performing tasks are called *executions* in Step Functions.  
For more information, see:  
[What is Step Functions?](welcome.md)
[Integrating services with Step Functions](integrate-services.md)

Lambda is well-suited for `Task` states, because Lambda functions are *serverless* and easy to write. You can write code in the AWS Management Console or your favorite editor. AWS handles the details of providing a computing environment for your function and running it.

## Step 1: Create a Lambda function
<a name="create-lambda-function"></a>

Your Lambda function receives event data and returns a greeting message.

**Important**  
Ensure that your Lambda function is under the same AWS account and AWS Region as your state machine.

1. Open the [Lambda console](https://console.aws.amazon.com/lambda/home) and choose **Create function**.

1. On the **Create function** page, choose **Author from scratch**.

1. For **Function name**, enter `HelloFunction`.

1. Keep the default selections for all other options, and then choose **Create function**. 

1. After your Lambda function is created, copy the function's Amazon Resource Name (ARN) displayed in the upper-right corner of the page. The following is an example ARN:

   ```
   arn:aws:lambda:region:123456789012:function:HelloFunction
   ```

1. Copy the following code for the Lambda function into the **Code source** section of the ***HelloFunction*** page.

   ```
   export const handler = async(event, context, callback) => {
       callback(null, "Hello from " + event.who + "!");
   };
   ```

   This code assembles a greeting using the `who` field of the input data, which is provided by the `event` object passed into your function. You add input data for this function later, when you [start a new execution](#start-lambda-function). The `callback` method returns the assembled greeting from your function.

1. Choose **Deploy**.

## Step 2: Test the Lambda function
<a name="test-lambda-function"></a>

Test your Lambda function to see it in operation.

1. Choose **Test**.

1. For **Event name**, enter `HelloEvent`.

1. Replace the **Event JSON** data with the following.

   ```
   {
       "who": "AWS Step Functions"
   }
   ```

   The `"who"` entry corresponds to the `event.who` field in your Lambda function, completing the greeting. You will input the same input data when you run your state machine.

1. Choose **Save** and then choose **Test**.

1. To review the test results, under **Execution result**, expand **Details**. 

## Step 3: Create a state machine
<a name="create-state-machine-step"></a>

Use the Step Functions console to create a state machine that invokes the Lambda function that you created in [Step 1](#create-lambda-function).

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.
**Important**  
Make sure that your state machine is under the same AWS account and Region as the Lambda function you created earlier.

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. In the [States browser](workflow-studio.md#workflow-studio-components-states) on the left, make sure you've chosen the **Actions** tab. Then, drag and drop the **AWS Lambda Invoke** API into the empty state labelled **Drag first state here**.

1. In the [Inspector](workflow-studio.md#workflow-studio-components-formdefinition) panel on the right, configure the Lambda function:

   1. In the **API Parameters** section, choose [the Lambda function that you created earlier](#create-lambda-function) in the **Function name** dropdown list.

   1. Keep the default selection in the **Payload** dropdown list.

1. (Optional) Choose **Definition** to view the state machine's [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition, which is automatically generated based on your selections in the **Actions** tab and ** Inspector** panel.

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For example, enter the name **LambdaStateMachine**.
**Note**  
Names of state machines, executions, and activity tasks must not exceed 80 characters in length. These names must be unique for your account and AWS Region, and must not contain any of the following:  
Whitespace
Wildcard characters (`? *`)
Bracket characters (`< > { } [ ]`)
Special characters (`" # % \ ^ | ~ ` $ & , ; : /`)
Control characters (`\\u0000` - `\\u001f` or `\\u007f` - `\\u009f`).
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, keep all the default selections in **State machine settings**.

1. Choose **Create**.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

## Step 4: Run the state machine
<a name="start-lambda-function"></a>

After you create your state machine, you can run it.

1. On the **State machines** page, choose **LambdaStateMachine**.

1. Choose **Start execution**.

   The **Start execution** dialog box is displayed.

1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

1. In the **Input** area, replace the example execution data with the following.

   ```
   {
       "who" : "AWS Step Functions"
   }
   ```

    `"who"` is the key name that your Lambda function uses to get the name of the person to greet.

1. Choose **Start Execution**.

   Your state machine's execution starts, and a new page showing your running execution is displayed.

1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

   To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

**Note**  
You can also pass payloads while invoking Lambda from a state machine. For more information and examples about invoking Lambda by passing payload in the `Parameters` field, see [Invoke an AWS Lambda function with Step Functions](connect-lambda.md).

# Deploying a workflow that waits for human approval in Step Functions
<a name="tutorial-human-approval"></a>

This tutorial shows you how to deploy a human approval project that allows an AWS Step Functions execution to pause during a task, and wait for a user to respond to an email. The workflow progresses to the next state once the user has approved the task to proceed. 

Deploying the CloudFormation stack included in this tutorial will create all necessary resources, including:
+ Amazon API Gateway resources
+ An AWS Lambda functions
+ An AWS Step Functions state machine
+ An Amazon Simple Notification Service email topic
+ Related AWS Identity and Access Management roles and permissions

**Note**  
You will need to provide a valid email address that you have access to when you create the CloudFormation stack.

For more information, see [Working with CloudFormation Templates](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-guide.html) and the `[AWS::StepFunctions::StateMachine](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html)` resource in the *AWS CloudFormation User Guide*.

## Step 1: Create an CloudFormation template
<a name="human-approval-deploy"></a>

1. Copy the example code from the [CloudFormation Template Source Code](#human-approval-yaml) section.

1. Paste the source of the CloudFormation template into a file on your local machine.

   For this example the file is called `human-approval.yaml`.

## Step 2: Create a stack
<a name="human-approval-create-stack"></a>

1. Log into the [CloudFormation console](https://console.aws.amazon.com/cloudformation/home).

1. Choose **Create Stack**, and then choose **With new resources (standard)**.

1. On the **Create stack** page, do the following:

   1. In the **Prerequisite - Prepare template** section, make sure **Template is ready** is selected.

   1. In the **Specify template** section, choose **Upload a template file** and then choose **Choose file** to upload the `human-approval.yaml` file you created earlier that includes the [template source code](#human-approval-yaml).

1. Choose **Next**.

1. On the **Specify stack details** page, do the following:

   1. For **Stack name**, enter a name for your stack.

   1. Under **Parameters**, enter a valid email address. You'll use this email address to subscribe to the Amazon SNS topic.

1. Choose **Next**, and then choose **Next** again.

1. On the **Review** page, choose **I acknowledge that CloudFormation might create IAM resources** and then choose **Create**.

   CloudFormation begins to create your stack and displays the **CREATE\$1IN\$1PROGRESS** status. When the process is complete, CloudFormation displays the **CREATE\$1COMPLETE** status.

1. (Optional) To display the resources in your stack, select the stack and choose the **Resources** tab.

## Step 3: Approve the Amazon SNS subscription
<a name="human-approval-approve-sub"></a>

Once the Amazon SNS topic is created, you will receive an email requesting that you confirm subscription.

1. Open the email account you provided when you created the CloudFormation stack.

1. Open the message **AWS Notification - Subscription Confirmation** from **no-reply@sns.amazonaws.com**

   The email will list the Amazon Resource Name for the Amazon SNS topic, and a confirmation link.

1. Choose the **confirm subscription** link.  
![\[Illustrative screenshot of a subscription confirmation email.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-human-approval-sub-conf.png)

## Step 4: Run the state machine
<a name="human-approval-run"></a>

1. On the **HumanApprovalLambdaStateMachine** page, choose **Start execution**.

   The **Start execution** dialog box is displayed.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. In the **Input** box, enter the following JSON input to run your workflow.

      ```
      {
          "Comment": "Testing the human approval tutorial."
      }
      ```

   1. Choose **Start execution**.

      The **ApprovalTest** state machine execution starts, and pauses at the **Lambda Callback** task.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).  
![\[Execution waiting for callback\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-human-approval-pause.png)

1. In the email account you used for the Amazon SNS topic earlier, open the message with the subject **Required approval from AWS Step Functions**. 

   The message includes separate URLs for **Approve** and **Reject**.

1. Choose the **Approve** URL.

   The workflow continues based on your choice.  
![\[Execution waiting for callback\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-human-approval-continue.png)

## CloudFormation Template Source Code
<a name="human-approval-yaml"></a>

Use this AWS CloudFormation template to deploy an example of a human approval process workflow.

```
AWSTemplateFormatVersion: "2010-09-09"
Description: "AWS Step Functions Human based task example. It sends an email with an HTTP URL for approval."
Parameters:
  Email:
    Type: String
    AllowedPattern: "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
    ConstraintDescription: Must be a valid email address.
Resources:
  # Begin API Gateway Resources
  ExecutionApi:
    Type: "AWS::ApiGateway::RestApi"
    Properties:
      Name: "Human approval endpoint"
      Description: "HTTP Endpoint backed by API Gateway and Lambda"
      FailOnWarnings: true

  ExecutionResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref ExecutionApi
      ParentId: !GetAtt "ExecutionApi.RootResourceId"
      PathPart: execution

  ExecutionMethod:
    Type: "AWS::ApiGateway::Method"
    Properties:
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        Type: AWS
        IntegrationHttpMethod: POST
        Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaApprovalFunction.Arn}/invocations"
        IntegrationResponses:
          - StatusCode: 302
            ResponseParameters:
              method.response.header.Location: "integration.response.body.headers.Location"
        RequestTemplates:
          application/json: |
            {
              "body" : $input.json('$'),
              "headers": {
                #foreach($header in $input.params().header.keySet())
                "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end

                #end
              },
              "method": "$context.httpMethod",
              "params": {
                #foreach($param in $input.params().path.keySet())
                "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end

                #end
              },
              "query": {
                #foreach($queryParam in $input.params().querystring.keySet())
                "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end

                #end
              }  
            }
      ResourceId: !Ref ExecutionResource
      RestApiId: !Ref ExecutionApi
      MethodResponses:
        - StatusCode: 302
          ResponseParameters:
            method.response.header.Location: true

  ApiGatewayAccount:
    Type: 'AWS::ApiGateway::Account'
    Properties:
      CloudWatchRoleArn: !GetAtt "ApiGatewayCloudWatchLogsRole.Arn"
  
  ApiGatewayCloudWatchLogsRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - apigateway.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: ApiGatewayLogsPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "logs:*"
                Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"

  ExecutionApiStage:
    DependsOn:
      - ApiGatewayAccount
    Type: 'AWS::ApiGateway::Stage'
    Properties:
      DeploymentId: !Ref ApiDeployment
      MethodSettings:
        - DataTraceEnabled: true
          HttpMethod: '*'
          LoggingLevel: INFO
          ResourcePath: /*
      RestApiId: !Ref ExecutionApi
      StageName: states

  ApiDeployment:
    Type: "AWS::ApiGateway::Deployment"
    DependsOn:
      - ExecutionMethod
    Properties:
      RestApiId: !Ref ExecutionApi
      StageName: DummyStage
  # End API Gateway Resources

  # Begin
  # Lambda that will be invoked by API Gateway
  LambdaApprovalFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile:
          Fn::Sub: |
            const { SFN: StepFunctions } = require("@aws-sdk/client-sfn");
            var redirectToStepFunctions = function(lambdaArn, statemachineName, executionName, callback) {
              const lambdaArnTokens = lambdaArn.split(":");
              const partition = lambdaArnTokens[1];
              const region = lambdaArnTokens[3];
              const accountId = lambdaArnTokens[4];

              console.log("partition=" + partition);
              console.log("region=" + region);
              console.log("accountId=" + accountId);

              const executionArn = "arn:" + partition + ":states:" + region + ":" + accountId + ":execution:" + statemachineName + ":" + executionName;
              console.log("executionArn=" + executionArn);

              const url = "https://console.aws.amazon.com/states/home?region=" + region + "#/executions/details/" + executionArn;
              callback(null, {
                  statusCode: 302,
                  headers: {
                    Location: url
                  }
              });
            };

            exports.handler = (event, context, callback) => {
              console.log('Event= ' + JSON.stringify(event));
              const action = event.query.action;
              const taskToken = event.query.taskToken;
              const statemachineName = event.query.sm;
              const executionName = event.query.ex;

              const stepfunctions = new StepFunctions();

              var message = "";

              if (action === "approve") {
                message = { "Status": "Approved! Task approved by ${Email}" };
              } else if (action === "reject") {
                message = { "Status": "Rejected! Task rejected by ${Email}" };
              } else {
                console.error("Unrecognized action. Expected: approve, reject.");
                callback({"Status": "Failed to process the request. Unrecognized Action."});
              }

              stepfunctions.sendTaskSuccess({
                output: JSON.stringify(message),
                taskToken: event.query.taskToken
              })
              .then(function(data) {
                redirectToStepFunctions(context.invokedFunctionArn, statemachineName, executionName, callback);
              }).catch(function(err) {
                console.error(err, err.stack);
                callback(err);
              });
            }
      Description: Lambda function that callback to AWS Step Functions
      FunctionName: LambdaApprovalFunction
      Handler: index.handler
      Role: !GetAtt "LambdaApiGatewayIAMRole.Arn"
      Runtime: nodejs18.x

  LambdaApiGatewayInvoke:
    Type: "AWS::Lambda::Permission"
    Properties:
      Action: "lambda:InvokeFunction"
      FunctionName: !GetAtt "LambdaApprovalFunction.Arn"
      Principal: "apigateway.amazonaws.com"
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ExecutionApi}/*"

  LambdaApiGatewayIAMRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          - Action:
              - "sts:AssumeRole"
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
      Policies:
        - PolicyName: CloudWatchLogsPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "logs:*"
                Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
        - PolicyName: StepFunctionsPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "states:SendTaskFailure"
                  - "states:SendTaskSuccess"
                Resource: "*"
  # End Lambda that will be invoked by API Gateway

  # Begin state machine that publishes to Lambda and sends an email with the link for approval
  HumanApprovalLambdaStateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      RoleArn: !GetAtt LambdaStateMachineExecutionRole.Arn
      DefinitionString:
        Fn::Sub: |
          {
              "StartAt": "Lambda Callback",
              "TimeoutSeconds": 3600,
              "States": {
                  "Lambda Callback": {
                      "Type": "Task",
                      "Resource": "arn:${AWS::Partition}:states:::lambda:invoke.waitForTaskToken",
                      "Parameters": {
                        "FunctionName": "${LambdaHumanApprovalSendEmailFunction.Arn}",
                        "Payload": {
                          "ExecutionContext.$": "$$",
                          "APIGatewayEndpoint": "https://${ExecutionApi}.execute-api.${AWS::Region}.amazonaws.com/states"
                        }
                      },
                      "Next": "ManualApprovalChoiceState"
                  },
                  "ManualApprovalChoiceState": {
                    "Type": "Choice",
                    "Choices": [
                      {
                        "Variable": "$.Status",
                        "StringEquals": "Approved! Task approved by ${Email}",
                        "Next": "ApprovedPassState"
                      },
                      {
                        "Variable": "$.Status",
                        "StringEquals": "Rejected! Task rejected by ${Email}",
                        "Next": "RejectedPassState"
                      }
                    ]
                  },
                  "ApprovedPassState": {
                    "Type": "Pass",
                    "End": true
                  },
                  "RejectedPassState": {
                    "Type": "Pass",
                    "End": true
                  }
              }
          }

  SNSHumanApprovalEmailTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        -
           Endpoint: !Sub ${Email}
           Protocol: email
  
  LambdaHumanApprovalSendEmailFunction:
    Type: "AWS::Lambda::Function"
    Properties:
      Handler: "index.lambda_handler"
      Role: !GetAtt LambdaSendEmailExecutionRole.Arn
      Runtime: "nodejs18.x"
      Timeout: "25"
      Code:
        ZipFile:
          Fn::Sub: |
            console.log('Loading function');
            const { SNS } = require("@aws-sdk/client-sns");
            exports.lambda_handler = (event, context, callback) => {
                console.log('event= ' + JSON.stringify(event));
                console.log('context= ' + JSON.stringify(context));

                const executionContext = event.ExecutionContext;
                console.log('executionContext= ' + executionContext);

                const executionName = executionContext.Execution.Name;
                console.log('executionName= ' + executionName);

                const statemachineName = executionContext.StateMachine.Name;
                console.log('statemachineName= ' + statemachineName);

                const taskToken = executionContext.Task.Token;
                console.log('taskToken= ' + taskToken);

                const apigwEndpint = event.APIGatewayEndpoint;
                console.log('apigwEndpint = ' + apigwEndpint)

                const approveEndpoint = apigwEndpint + "/execution?action=approve&ex=" + executionName + "&sm=" + statemachineName + "&taskToken=" + encodeURIComponent(taskToken);
                console.log('approveEndpoint= ' + approveEndpoint);

                const rejectEndpoint = apigwEndpint + "/execution?action=reject&ex=" + executionName + "&sm=" + statemachineName + "&taskToken=" + encodeURIComponent(taskToken);
                console.log('rejectEndpoint= ' + rejectEndpoint);

                const emailSnsTopic = "${SNSHumanApprovalEmailTopic}";
                console.log('emailSnsTopic= ' + emailSnsTopic);

                var emailMessage = 'Welcome! \n\n';
                emailMessage += 'This is an email requiring an approval for a step functions execution. \n\n'
                emailMessage += 'Check the following information and click "Approve" link if you want to approve. \n\n'
                emailMessage += 'Execution Name -> ' + executionName + '\n\n'
                emailMessage += 'Approve ' + approveEndpoint + '\n\n'
                emailMessage += 'Reject ' + rejectEndpoint + '\n\n'
                emailMessage += 'Thanks for using Step functions!'
                
                const sns = new SNS();
                var params = {
                  Message: emailMessage,
                  Subject: "Required approval from AWS Step Functions",
                  TopicArn: emailSnsTopic
                };

                sns.publish(params)
                  .then(function(data) {
                    console.log("MessageID is " + data.MessageId);
                    callback(null);
                  }).catch(
                    function(err) {
                    console.error(err, err.stack);
                    callback(err);
                  });
            }

  LambdaStateMachineExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service: states.amazonaws.com
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: InvokeCallbackLambda
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "lambda:InvokeFunction"
                Resource:
                  - !Sub "${LambdaHumanApprovalSendEmailFunction.Arn}"

  LambdaSendEmailExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: CloudWatchLogsPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
        - PolicyName: SNSSendEmailPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "SNS:Publish"
                Resource:
                  - !Sub "${SNSHumanApprovalEmailTopic}"

# End state machine that publishes to Lambda and sends an email with the link for approval
Outputs:
  ApiGatewayInvokeURL:
    Value: !Sub "https://${ExecutionApi}.execute-api.${AWS::Region}.amazonaws.com/states"
  StateMachineHumanApprovalArn:
    Value: !Ref HumanApprovalLambdaStateMachine
```

# Using Inline Map state to repeat an action in Step Functions
<a name="tutorial-map-inline"></a>

This tutorial helps you get started with using the `Map` state in Inline mode. You use the *Inline Map state* in your workflows to repeatedly perform an action. For more information about Inline mode, see [Map state in Inline mode](state-map-inline.md).

In this tutorial, you use the *Inline Map state* to repeatedly generate version 4 universally unique identifiers (v4 UUID). You start by creating a workflow that contains two [Pass workflow state](state-pass.md) states and an *Inline Map state* in the Workflow Studio. Then, you configure the input and output, including the input JSON array for the `Map` state. The `Map` state returns an output array that contains the v4 UUIDs generated for each item in the input array.

## Step 1: Create the workflow prototype
<a name="use-inline-map-create-workflow"></a>

In this step, you create the prototype for your workflow using Workflow Studio. Workflow Studio is a visual workflow designer available in the Step Functions console. You’ll choose the required states from the **Flow** tab and use the drag and drop feature of Workflow Studio to create the workflow prototype.

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. From the **Flow** tab, drag a **Pass** state and drop it to the empty state labelled **Drag first state here**.

1. Drag a **Map** state and drop it below the **Pass** state. Rename the **Map** state to **Map demo**.

1. Drag a second **Pass** state and drop it inside of the **Map demo** state.

1. Rename the second **Pass** state to **Generate UUID**.

## Step 2: Configure input and output
<a name="use-inline-map-configure-io"></a>

In this step, you configure input and output for all the states in your workflow prototype. First, you inject some fixed data into the workflow using the first **Pass** state. This **Pass** state passes on this data as input to the **Map demo** state. Within this input, you specify the node that contains the input array the **Map demo** state should iterate over. Then you define the step that the **Map demo** state should repeat to generate the v4 UUIDs. Finally, you configure the output to return for each repetition.

1. Choose the first **Pass** state in your workflow prototype. In the **Output** tab, enter the following under **Result**:

   ```
   {
     "foo": "bar",
     "colors": [
       "red",
       "green",
       "blue",
       "yellow",
       "white"
     ]
   }
   ```

1. Choose the **Map demo** state and in the **Configuration** tab, do the following:

   1. Choose **Provide a path to items array**.

   1. Specify the following [reference path](amazon-states-language-paths.md#amazon-states-language-reference-paths) to select the node that contains the input array: 

      ```
      $.colors
      ```

1. Choose the **Generate UUID** state and in the **Input** tab, do the following:

   1. Choose **Transform input with Parameters**.

   1. Enter the following JSON input to generate the v4 UUIDs for each of the input array items. You use the `States.UUID` intrinsic function to generate the UUIDs.

      ```
      {
        "uuid.$": "States.UUID()"
      }
      ```

1. For the **Generate UUID** state, choose the **Output** tab and do the following:

   1. Choose **Filter output with OutputPath**.

   1. Enter the following reference path to select the JSON node that contains the output array items: 

      ```
      $.uuid
      ```

## Step 3: Review and save auto-generated definition
<a name="use-inline-map-review-asl-def"></a>

As you drag and drop states from the **Flow** panel onto the canvas, Workflow Studio automatically composes the [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition of your workflow in real-time. You can edit this definition as required.

1. (Optional) Choose **Definition** on the [Inspector panel](workflow-studio.md#workflow-studio-components-formdefinition) panel to view the automatically-generated Amazon States Language definition of your workflow.
**Tip**  
You can also view the ASL definition in the [Code editor](workflow-studio.md#wfs-interface-code-editor) of Workflow Studio. In the code editor, you can also edit the ASL definition of your workflow.

   The following example shows the automatically generated Amazon States Language definition for your workflow.

   ```
   {
       "Comment": "Using Map state in Inline mode",
       "StartAt": "Pass",
       "States": {
         "Pass": {
           "Type": "Pass",
           "Next": "Map demo",
           "Result": {
             "foo": "bar",
             "colors": [
               "red",
               "green",
               "blue",
               "yellow",
               "white"
             ]
           }
         },
         "Map demo": {
           "Type": "Map",
           "ItemsPath": "$.colors",
           "ItemProcessor": {
             "ProcessorConfig": {
               "Mode": "INLINE"
             },
             "StartAt": "Generate UUID",
             "States": {
               "Generate UUID": {
                 "Type": "Pass",
                 "End": true,
                 "Parameters": {
                   "uuid.$": "States.UUID()"
                 },
                 "OutputPath": "$.uuid"
               }
             }
           },
           "End": true
         }
       }
     }
   ```

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **InlineMapDemo**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, keep all the default selections in **State machine configuration**.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

## Step 4: Run the state machine
<a name="use-inline-map-sm-run"></a>

State machine executions are instances where you run your workflow to perform tasks.

1. On the **InlineMapDemo** page, choose **Start execution**.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. (Optional) In the **Input** box, enter input values in JSON format to run your workflow.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID, known as the *Execution Details* page. You can review the execution results as the workflow progresses and after it completes.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

   To view the execution input and output side-by-side, choose **Execution input and output**. Under **Output**, view the output array returned by the `Map` state. The following is an example of the output array:

   ```
   [
     "a85cbc7b-4e65-4ac2-97af-80ed504adc1d",
     "b05bca11-d481-414e-aa9a-88285ec6590d",
     "f42d59f7-bd32-480f-b270-caddb518ce2a",
     "15f18616-517d-4b69-b7c3-bf22222d2efd",
     "690bcfee-6d58-408c-a6b4-1995ccafdbd2"
   ]
   ```

# Copying large-scale CSV data using Distributed Map in Step Functions
<a name="tutorial-map-distributed"></a>

This tutorial helps you start using the `Map` state in Distributed mode. A `Map` state set to **Distributed** is known as a *Distributed Map state*. You use the *Distributed Map state* in your workflows to iterate over large-scale Amazon S3 data sources. The `Map` state runs each iteration as a child workflow execution, which enables high concurrency. For more information about Distributed mode, see [Map state in Distributed mode](state-map-distributed.md).

In this tutorial, you use the *Distributed Map state* to iterate over a CSV file in an Amazon S3 bucket. You then return its contents, along with the ARN of a child workflow execution, in another Amazon S3 bucket. You start by creating a workflow prototype in the Workflow Studio. Next, you set the [`Map` state's processing mode](state-map.md#concepts-map-process-modes) to Distributed, specify the CSV file as the dataset, and provide its location to the `Map` state. You also specify the workflow type for the child workflow executions that the *Distributed Map state* starts as **Express**.

In addition to these settings, you also specify other configurations, such as the maximum number of concurrent child workflow executions and the location to export the `Map` result, for the example workflow used in this tutorial.

## Prerequisites
<a name="use-dist-map-prereqs"></a>
+ Upload a CSV file to an Amazon S3 bucket. You must define a header row within your CSV file. For information about size limits imposed on the CSV file and how to specify the header row, see [CSV file in an Amazon S3 bucket](input-output-itemreader.md#itemsource-example-csv-data).
+ Create another Amazon S3 bucket and a folder within that bucket to export the `Map` state result to.

**Requirements for account and region**  
Your Amazon S3 buckets must be in the same AWS account and AWS Region as your state machine.  
Note that even though your state machine may be able to access files in buckets across different AWS accounts that are in the same AWS Region, Step Functions only supports listing objects in Amazon S3 buckets that are in *both* the same AWS account and the same AWS Region as the state machine.

## Step 1: Create the workflow prototype
<a name="use-dist-map-create-workflow"></a>

In this step, you create the prototype for your workflow using Workflow Studio. Workflow Studio is a visual workflow designer available in the Step Functions console. You choose the required state and API action from the **Flow** and **Actions** tabs respectively. You'll use the drag and drop feature of Workflow Studio to create the workflow prototype.

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. From the **Flow** tab, drag a **Map** state and drop it to the empty state labelled **Drag first state here**.

1. In the **Configuration** tab, for **State name**, enter **Process data**.

1. From the **Actions** tab, drag an **AWS Lambda Invoke** API action and drop it inside the **Process data** state.

1. Rename the **AWS Lambda Invoke** state to **Process CSV data**.

## Step 2: Configure the required fields for Map state
<a name="use-dist-map-config-fields"></a>

In this step, you configure the following required fields of the *Distributed Map state*:
+ [ItemReader](input-output-itemreader.md) – Specifies the dataset and its location from which the `Map` state can read input.
+ [ItemProcessor](state-map-distributed.md#distitemprocessor) – Specifies the following values:
  + `ProcessorConfig` – Set the `Mode` and `ExecutionType` to `DISTRIBUTED` and `EXPRESS` respectively. This sets the `Map` state's processing mode and the workflow type for child workflow executions that the *Distributed Map state* starts.
  + `StartAt` – The first state in the Map workflow.
  + `States` – Defines the Map workflow, which is a set of steps to repeat in each child workflow execution.
+ [ResultWriter](input-output-resultwriter.md) – Specifies the Amazon S3 location where Step Functions writes the *Distributed Map state* results.
**Important**  
Make sure that the Amazon S3 bucket you use to export the results of a Map Run is under the same AWS account and AWS Region as your state machine. Otherwise, your state machine execution will fail with the `States.ResultWriterFailed` error.

**To configure the required fields:**

1. Choose the **Process data** state and, in the **Configuration** tab, do the following:

   1. For **Processing mode**, choose **Distributed**.

   1. For **Item source**, choose **Amazon S3**, and then choose **CSV file in S3** from the **S3 item source** dropdown list.

   1. Do the following to specify the Amazon S3 location of your CSV file:

      1. For **S3 object**, select **Enter bucket and key** from the dropdown list.

      1. For **Bucket**, enter the name of the Amazon S3 bucket, which contains the CSV file. For example, **amzn-s3-demo-source-bucket**.

      1. For **Key**, enter the name of the Amazon S3 object in which you saved the CSV file. You must also specify the name of the CSV file in this field. For example, **csvDataset/ratings.csv**.

   1. For CSV files, you must also specify the location of the column header. To do this, choose **Additional configuration**, and then for **CSV header location** keep the default selection of **First row** if the first row of your CSV file is the header. Otherwise, choose **Given** to specify the header within the state machine definition. For more information, see `ReaderConfig`.

   1. For **Child execution type**, choose **Express**.

1. In **Export location**, to export the Map Run results to a specific Amazon S3 location, choose **Export Map state's output to Amazon S3**.

1. Do the following:

   1. For **S3 bucket**, choose **Enter bucket name and prefix** from the dropdown list.

   1. For **Bucket**, enter the name of the Amazon S3 bucket where you want to export the results to. For example, **mapOutputs**.

   1. For **Prefix**, enter the folder name where you want to save the results to. For example, **resultData**.

## Step 3: Configure additional options
<a name="use-dist-map-config-misc-fields"></a>

In addition to the required settings for a *Distributed Map state*, you can also specify other options. These can include the maximum number of concurrent child workflow executions and the location to export the `Map` state result to.

1. Choose the **Process data** state. Then, in **Item source**, choose **Additional configuration**.

1. Do the following:

   1. Choose **Modify items with ItemSelector** to specify a custom JSON input for each child workflow execution.

   1. Enter the following JSON input:

      ```
      {
        "index.$": "$$.Map.Item.Index",
        "value.$": "$$.Map.Item.Value"
      }
      ```

      For information about how to create a custom input, see `ItemSelector (Map)`.

1. In **Runtime settings**, for **Concurrency limit**, specify the number of concurrent child workflow executions that the *Distributed Map state* can start. For example, enter **100**.

1. Open a new window or tab on your browser and complete the configuration of the Lambda function you'll use in this workflow, as explained in [Step 4: Configure the Lambda function](#use-dist-map-config-resource).

## Step 4: Configure the Lambda function
<a name="use-dist-map-config-resource"></a>

**Important**  
Ensure that your Lambda function is under the same AWS Region as your state machine.

1. Open the [Lambda console](https://console.aws.amazon.com/lambda/home) and choose **Create function**.

1. On the **Create function** page, choose **Author from scratch**.

1. In the **Basic information** section, configure your Lambda function:

   1. For **Function name**, enter **distributedMapLambda**.

   1. For **Runtime**, choose **Node.js**.

   1. Keep all of the default selections and choose **Create function**.

   1. After you create your Lambda function, copy the function's Amazon Resource Name (ARN) displayed in the upper-right corner of the page. You'll need to provide this in your workflow prototype. The following is an example ARN:

      ```
      arn:aws:lambda:us-east-2:123456789012:function:distributedMapLambda
      ```

1. Copy the following code for the Lambda function and paste it into the **Code source** section of the **distributedMapLambda** page.

   ```
   exports.handler = async function(event, context) {
       console.log("Received Input:\n", event);
   
       return {
           'statusCode' : 200,
           'inputReceived' : event //returns the input that it received
       }
   };
   ```

1. Choose **Deploy**. Once your function deploys, choose **Test** to see the output of your Lambda function.

## Step 5: Update the workflow prototype
<a name="use-dist-map-update-workflow"></a>

In the Step Functions console, you'll update your workflow to add the Lambda function's ARN.

1. Return to the tab or window where you created the workflow prototype.

1. Choose the **Process CSV data** step, and in the **Configuration** tab, do the following:

   1. For **Integration type**, choose **Optimized**.

   1. For **Function name**, start to enter the name of your Lambda function. Choose the function from the dropdown list that appears, or choose **Enter function name** and provide the Lambda function ARN.

## Step 6: Review the auto-generated Amazon States Language definition and save the workflow
<a name="use-dist-map-review-asl"></a>

As you drag and drop states from the **Action** and **Flow** tabs onto the canvas, Workflow Studio automatically composes the [Amazon States Language](concepts-amazon-states-language.md) definition of your workflow in real-time. You can edit this definition as required.

1. (Optional) Choose **Definition** on the [Inspector panel](workflow-studio.md#workflow-studio-components-formdefinition) panel and view the state machine definition.
**Tip**  
You can also view the ASL definition in the [Code editor](workflow-studio.md#wfs-interface-code-editor) of Workflow Studio. In the code editor, you can also edit the ASL definition of your workflow.

   The following example code shows the automatically generated Amazon States Language definition for your workflow.

   ```
   {
     "Comment": "Using Map state in Distributed mode",
     "StartAt": "Process data",
     "States": {
       "Process data": {
         "Type": "Map",
         "MaxConcurrency": 100,
         "ItemReader": {
           "ReaderConfig": {
             "InputType": "CSV",
             "CSVHeaderLocation": "FIRST_ROW"
           },
           "Resource": "arn:aws:states:::s3:getObject",
           "Parameters": {
             "Bucket": "amzn-s3-demo-source-bucket",
             "Key": "csvDataset/ratings.csv"
           }
         },
         "ItemProcessor": {
           "ProcessorConfig": {
             "Mode": "DISTRIBUTED",
             "ExecutionType": "EXPRESS"
           },
           "StartAt": "Process CSV data",
           "States": {
             "Process CSV data": {
               "Type": "Task",
               "Resource": "arn:aws:states:::lambda:invoke",
               "OutputPath": "$.Payload",
               "Parameters": {
                 "Payload.$": "$",
                 "FunctionName": "arn:aws:lambda:us-east-2:account-id:function:distributedMapLambda"
               },
               "End": true
             }
           }
         },
         "Label": "Processdata",
         "End": true,
         "ResultWriter": {
           "Resource": "arn:aws:states:::s3:putObject",
           "Parameters": {
             "Bucket": "mapOutputs",
             "Prefix": "resultData"
           }
         },
         "ItemSelector": {
           "index.$": "$$.Map.Item.Index",
           "value.$": "$$.Map.Item.Value"
         }
       }
     }
   }
   ```

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **DistributedMapDemo**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, keep all the default selections in **State machine configuration**.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

## Step 7: Run the state machine
<a name="use-dist-map-sm-run"></a>

An *execution* is an instance of your state machine where you run your workflow to perform tasks.

1. On the **DistributedMapDemo** page, choose **Start execution**.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. (Optional) In the **Input** box, enter input values in JSON format to run your workflow.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID, known as the *Execution Details* page. You can review the execution results as the workflow progresses and after it completes.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

   For example, choose the `Map` state, and then choose **Map Run** to open the *Map Run Details* page. On this page, you can view all the execution details of the *Distributed Map state* and the child workflow executions that it started. For information about this page, see [Viewing Map Runs](concepts-examine-map-run.md).

# Iterate a loop with a Lambda function in Step Functions
<a name="tutorial-create-iterate-pattern-section"></a>

In this tutorial, you implement a design pattern that uses a state machine and an AWS Lambda function to iterate a loop a specific number of times. 

Use this design pattern any time you need to keep track of the number of loops in a state machine. This implementation can help you break up large tasks or long-running executions into smaller chunks, or to end an execution after a specific number of events. You can use a similar implementation to periodically end and restart a long-running execution to avoid exceeding service quotas for AWS Step Functions, AWS Lambda, or other AWS services.

Before you begin, go through the [Creating a Step Functions state machine that uses Lambda](tutorial-creating-lambda-state-machine.md) tutorial to ensure you are familiar with using Lambda and Step Functions together.

## Step 1: Create a Lambda function to iterate a count
<a name="create-iterate-pattern-step-1"></a>

By using a Lambda function you can track the number of iterations of a loop in your state machine. The following Lambda function receives input values for `count`, `index`, and `step`. It returns these values with an updated `index` and a Boolean value named `continue`. The Lambda function sets `continue` to `true` if the `index` is less than `count`.

Your state machine then implements a `Choice` state that executes some application logic if `continue` is `true`, or exits if it is `false`.

### To create the Lambda function
<a name="create-iterate-pattern-create-lambda-function"></a>

1. Sign in to the [Lambda console](https://console.aws.amazon.com/lambda/home), and then choose **Create function**.

1. On the **Create function** page, choose **Author from scratch**.

1. In the **Basic information** section, configure your Lambda function, as follows:

   1. For **Function name**, enter `Iterator`.

   1. For **Runtime**, choose **Node.js**.

   1. In **Change default execution role**, choose **Create a new role with basic Lambda permissions**.

   1. Choose **Create function**.

1. Copy the following code for the Lambda function into the **Code source**.

   ```
   export const handler = function (event, context, callback) {
     let index = event.iterator.index
     let step = event.iterator.step
     let count = event.iterator.count
    
     index = index + step
    
     callback(null, {
       index,
       step,
       count,
       continue: index < count
     })
   }
   ```

   This code accepts input values for `count`, `index`, and `step`. It increments the `index` by the value of `step` and returns these values, and the Boolean `continue`. The value of `continue` is `true` if `index` is less than `count`.

1. Choose **Deploy**.

## Step 2: Test the Lambda Function
<a name="create-iterate-pattern-step-2"></a>

Run your Lambda function with numeric values to see it in operation. You can provide input values for your Lambda function that mimic an iteration. 

### To test your Lambda function
<a name="create-iterate-pattern-test-lambda-function"></a>

1. Choose **Test**.

1. In the **Configure test event** dialog box, enter `TestIterator` in the **Event name** box.

1. Replace the example data with the following.

   ```
   {
     "Comment": "Test my Iterator function",
     "iterator": {
       "count": 10,
       "index": 5,
       "step": 1
     }
   }
   ```

   These values mimic what would come from your state machine during an iteration. The Lambda function will increment the index and return `true` for `continue` when the index is less than `count`. For this test, the index has already incremented to `5`. The test will increment `index` to `6` and set `continue` to `true`.

1. Choose **Create**.

1. Choose **Test** to test your Lambda function.

   The results of the test are displayed in the **Execution results** tab. 

1. Choose the **Execution results** tab to see the output.

   ```
   {
     "index": 6,
     "step": 1,
     "count": 10,
     "continue": true
   }
   ```
**Note**  
If you set `index` to `9` and test again, the `index` increments to `10`, and `continue` will be `false`.

## Step 3: Create a State Machine
<a name="create-iterate-pattern-step-3"></a>

**Before you leave the Lambda console…**  
Copy the Lambda function ARN. Paste it into a note. You'll need it in the next step.

Next, you will create a state machine with the following states:
+ `ConfigureCount` – Sets default values for `count`, `index`, and `step`.
+ `Iterator` – Refers to the Lambda function you created earlier, passing in the values configured in `ConfigureCount`.
+ `IsCountReached` – A choice state that continues the loop or proceeds to `Done` state, based on the value returned from your `Iterator` function.
+ `ExampleWork` – A stub for work that needs to be done. In this example, the workflow has a `Pass` state, but in a real solution, you would likely use a `Task`.
+ `Done` – End state of your workflow.

To create the state machine in the console:

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), and then choose **Create a state machine**.
**Important**  
Your state machine must be in the same AWS account and Region as your Lambda function.

1. Select the **Blank** template.

1. In the **Code** pane, paste the following JSON which defines the state machine.

   For more information about the Amazon States Language, see [State Machine Structure](statemachine-structure.md).

   ```
   {
       "Comment": "Iterator State Machine Example",
       "StartAt": "ConfigureCount",
       "States": {
           
           "ConfigureCount": {
               "Type": "Pass",
               "Result": {
                   "count": 10,
                   "index": 0,
                   "step": 1
               },
               "ResultPath": "$.iterator",
               "Next": "Iterator"
           },
           "Iterator": {
               "Type": "Task",
               "Resource": "arn:aws:lambda:region:123456789012:function:Iterate",
               "ResultPath": "$.iterator",
               "Next": "IsCountReached"
           },
           "IsCountReached": {
               "Type": "Choice",
               "Choices": [
                   {
                       "Variable": "$.iterator.continue",
                       "BooleanEquals": true,
                       "Next": "ExampleWork"
                   }
               ],
               "Default": "Done"
           },
           "ExampleWork": {
               "Comment": "Your application logic, to run a specific number of times",
               "Type": "Pass",
               "Result": {
                 "success": true
               },
               "ResultPath": "$.result",
               "Next": "Iterator"
           },
           "Done": {
               "Type": "Pass",
               "End": true
             
           }
       }
   }
   ```

1. Replace the `Iterator Resource` field with the ARN for your `Iterator` Lambda function that you created earlier.

1. Select **Config**, and enter a **Name** for your state machine, such as `IterateCount`.
**Note**  
Names of state machines, executions, and activity tasks must not exceed 80 characters in length. These names must be unique for your account and AWS Region, and must not contain any of the following:  
Whitespace
Wildcard characters (`? *`)
Bracket characters (`< > { } [ ]`)
Special characters (`" # % \ ^ | ~ ` $ & , ; : /`)
Control characters (`\\u0000` - `\\u001f` or `\\u007f` - `\\u009f`).
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

1. For **Type**, accept default value of **Standard**. For **Permissions**, choose **Create new role**.

1. Choose **Create**, and then **Confirm** the role creations.

## Step 4: Start a New Execution
<a name="create-iterate-pattern-step-4"></a>

After you create your state machine, you can start an execution.

1. On the **IterateCount** page, choose **Start execution**.

1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

1. Choose **Start Execution**.

   A new execution of your state machine starts, showing your running execution.  
![\[State machine graph showing blue iterator state indicating in progress status.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-create-iterate-running.png)

   The execution increments in steps, tracking the count using your Lambda function. On each iteration, it performs the example work referenced in the `ExampleWork` state in your state machine. 

   When the count reaches the number specified in the `ConfigureCount` state in your state machine, the execution quits iterating and ends.   
![\[State machine graph showing Iterator and Done state in green to indicate both have succeeded.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-create-iterate-done.png)

# Processing batch data with a Lambda function in Step Functions
<a name="tutorial-itembatcher-param-task"></a>

In this tutorial, you use the *Distributed Map state*'s [ItemBatcher (Map)](input-output-itembatcher.md) field to process an entire batch of items inside a Lambda function. Each batch contains a maximum of three items. The *Distributed Map state* starts four child workflow executions, where each execution processes three items, while one execution processes a single item. Each child workflow execution invokes a Lambda function that iterates over the individual items present in the batch.

You'll create a state machine that performs multiplication on an array of integers. Say that the integer array you provide as input is `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]` and the multiplication factor is `7`. Then, the resulting array formed after multiplying these integers with a factor of 7, will be `[7, 14, 21, 28, 35, 42, 49, 56, 63, 70]`.

## Step 1: Create the state machine
<a name="itembatcher-param-task-create-state-machine"></a>

In this step, you create the workflow prototype of the state machine that passes an entire batch of data to the Lambda function you'll create in [Step 2](#itembatcher-param-task-config-resource).
+ Use the following definition to create a state machine using the [Step Functions console](https://console.aws.amazon.com/states/home?region=us-east-1#/). For information about creating a state machine, see [Step 1: Create the workflow prototype](tutorial-map-distributed.md#use-dist-map-create-workflow) in the [Getting started with using Distributed Map state](tutorial-map-distributed.md) tutorial.

  In this state machine, you define a *Distributed Map state* that accepts an array of 10 integers as input and passes this array to a Lambda function in batches of `3`. The Lambda function iterates over the individual items present in the batch and returns an output array named `multiplied`. The output array contains the result of the multiplication performed on the items passed in the input array.
**Important**  
Make sure to replace the Amazon Resource Name (ARN) of the Lambda function in the following code with the ARN of the function you'll create in [Step 2](#itembatcher-param-task-config-resource).

  ```
  {
    "StartAt": "Pass",
    "States": {
      "Pass": {
        "Type": "Pass",
        "Next": "Map",
        "Result": {
          "MyMultiplicationFactor": 7,
          "MyItems": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        }
      },
      "Map": {
        "Type": "Map",
        "ItemProcessor": {
          "ProcessorConfig": {
            "Mode": "DISTRIBUTED",
            "ExecutionType": "STANDARD"
          },
          "StartAt": "Lambda Invoke",
          "States": {
            "Lambda Invoke": {
              "Type": "Task",
              "Resource": "arn:aws:states:::lambda:invoke",
              "OutputPath": "$.Payload",
              "Parameters": {
                "Payload.$": "$",
                "FunctionName": "arn:aws:lambda:region:account-id:function:functionName"
              },
              "Retry": [
                {
                  "ErrorEquals": [
                    "Lambda.ServiceException",
                    "Lambda.AWSLambdaException",
                    "Lambda.SdkClientException",
                    "Lambda.TooManyRequestsException"
                  ],
                  "IntervalSeconds": 2,
                  "MaxAttempts": 6,
                  "BackoffRate": 2
                }
              ],
              "End": true
            }
          }
        },
        "End": true,
        "Label": "Map",
        "MaxConcurrency": 1000,
        "ItemBatcher": {
          "MaxItemsPerBatch": 3,
          "BatchInput": {
            "MyMultiplicationFactor.$": "$.MyMultiplicationFactor"
          }
        },
        "ItemsPath": "$.MyItems"
      }
    }
  }
  ```

## Step 2: Create the Lambda function
<a name="itembatcher-param-task-config-resource"></a>

In this step, you create the Lambda function that processes all the items passed in the batch.

**Important**  
Ensure that your Lambda function is under the same AWS Region as your state machine.

**To create the Lambda function**

1. Use the [Lambda console](https://console.aws.amazon.com/lambda/home) to create a **Python** Lambda function named **ProcessEntireBatch**. For information about creating a Lambda function, see [Step 4: Configure the Lambda function](tutorial-map-distributed.md#use-dist-map-config-resource) in the [Getting started with using Distributed Map state](tutorial-map-distributed.md) tutorial.

1. Copy the following code for the Lambda function and paste it into the **Code source** section of your Lambda function.

   ```
   import json
   
   def lambda_handler(event, context):
       multiplication_factor = event['BatchInput']['MyMultiplicationFactor']
       items = event['Items']
       
       results = [multiplication_factor * item for item in items]
       
       return {
           'statusCode': 200,
           'multiplied': results
       }
   ```

1. After you create your Lambda function, copy the function's ARN displayed in the upper-right corner of the page. The following is an example ARN, where *`function-name`* is the name of the Lambda function (in this case, `ProcessEntireBatch`):

   ```
   arn:aws:lambda:region:123456789012:function:function-name
   ```

   You'll need to provide the function ARN in the state machine you created in [Step 1](#itembatcher-param-task-create-state-machine).

1. Choose **Deploy** to deploy the changes.

## Step 3: Run the state machine
<a name="itembatcher-param-task-run-state-machine"></a>

When you run the [state machine](#itembatcher-param-task-create-state-machine), the *Distributed Map state* starts four child workflow executions, where each execution processes three items, while one execution processes a single item.

The following example shows the data passed to the [`ProcessEntireBatch`](#itembatcher-param-task-config-resource) function by one of the child workflow executions.

```
{
  "BatchInput": {
    "MyMultiplicationFactor": 7
  },
  "Items": [1, 2, 3]
}
```

Given this input, the following example shows the output array named `multiplied` that is returned by the Lambda function.

```
{
  "statusCode": 200,
  "multiplied": [7, 14, 21]
}
```

The state machine returns the following output that contains four arrays named `multiplied` for the four child workflow executions. These arrays contain the multiplication results of the individual input items.

```
[
  {
    "statusCode": 200,
    "multiplied": [7, 14, 21]
  },
  {
    "statusCode": 200,
    "multiplied": [28, 35, 42]
  },
  {
    "statusCode": 200,
    "multiplied": [49, 56, 63]
  },
  {
    "statusCode": 200,
    "multiplied": [70]
  }
]
```

To combine all the array items returned into a single output array, you can use the [ResultSelector](input-output-inputpath-params.md#input-output-resultselector) field. Define this field inside the *Distributed Map state* to find all the `multiplied` arrays, extract all the items inside these arrays, and then combine them into a single output array.

To use the `ResultSelector` field, update your state machine definition as shown in the following example.

```
{
  "StartAt": "Pass",
  "States": {
    ...
    ...
    "Map": {
      "Type": "Map",
      ...
      ...
      "ItemsPath": "$.MyItems",
      "ResultSelector": {
        "multiplied.$": "$..multiplied[*]"
      }
    }
  }
}
```

The updated state machine returns a consolidated output array as shown in the following example.

```
{
  "multiplied": [7, 14, 21, 28, 35, 42, 49, 56, 63, 70]
}
```

# Processing individual items with a Lambda function in Step Functions
<a name="tutorial-itembatcher-single-item-process"></a>

In this tutorial, you use the *Distributed Map state*'s [ItemBatcher (Map)](input-output-itembatcher.md) field to iterate over individual items present in a batch using a Lambda function. The *Distributed Map state* starts four child workflow executions. Each of these child workflows runs an *Inline Map state*. For its each iteration, the *Inline Map state* invokes a Lambda function and passes a single item from the batch to the function. The Lambda function then processes the item and returns the result.

You'll create a state machine that performs multiplication on an array of integers. Say that the integer array you provide as input is `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]` and the multiplication factor is `7`. Then, the resulting array formed after multiplying these integers with a factor of 7, will be `[7, 14, 21, 28, 35, 42, 49, 56, 63, 70]`.

## Step 1: Create the state machine
<a name="itembatcher-single-item-process-create-state-machine"></a>

In this step, you create the workflow prototype of the state machine that passes a single item from a batch of items to each invocation of the Lambda function you'll create in [Step 2](#itembatcher-single-item-process-config-resource).
+ Use the following definition to create a state machine using the [Step Functions console](https://console.aws.amazon.com/states/home?region=us-east-1#/). For information about creating a state machine, see [Step 1: Create the workflow prototype](tutorial-map-distributed.md#use-dist-map-create-workflow) in the [Getting started with using Distributed Map state](tutorial-map-distributed.md) tutorial.

  In this state machine, you define a *Distributed Map state* that accepts an array of 10 integers as input and passes these array items to the child workflow executions in batches. Each child workflow execution receives a batch of three items as input and runs an *Inline Map state*. Every iteration of the *Inline Map state* invokes a Lambda function and passes an item from the batch to the function. This function then multiplies the item with a factor of `7` and returns the result.

  The output of each child workflow execution is a JSON array that contains the multiplication result for each of the items passed.
**Important**  
Make sure to replace the Amazon Resource Name (ARN) of the Lambda function in the following code with the ARN of the function you'll create in [Step 2](#itembatcher-single-item-process-config-resource).

  ```
  {
    "StartAt": "Pass",
    "States": {
      "Pass": {
        "Type": "Pass",
        "Next": "Map",
        "Result": {
          "MyMultiplicationFactor": 7,
          "MyItems": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        }
      },
      "Map": {
        "Type": "Map",
        "ItemProcessor": {
          "ProcessorConfig": {
            "Mode": "DISTRIBUTED",
            "ExecutionType": "STANDARD"
          },
          "StartAt": "InnerMap",
          "States": {
            "InnerMap": {
              "Type": "Map",
              "ItemProcessor": {
                "ProcessorConfig": {
                  "Mode": "INLINE"
                },
                "StartAt": "Lambda Invoke",
                "States": {
                  "Lambda Invoke": {
                    "Type": "Task",
                    "Resource": "arn:aws:states:::lambda:invoke",
                    "OutputPath": "$.Payload",
                    "Parameters": {
                      "Payload.$": "$",
                      "FunctionName": "arn:aws:lambda:region:account-id:function:functionName"
                    },
                    "Retry": [
                      {
                        "ErrorEquals": [
                          "Lambda.ServiceException",
                          "Lambda.AWSLambdaException",
                          "Lambda.SdkClientException",
                          "Lambda.TooManyRequestsException"
                        ],
                        "IntervalSeconds": 2,
                        "MaxAttempts": 6,
                        "BackoffRate": 2
                      }
                    ],
                    "End": true
                  }
                }
              },
              "End": true,
              "ItemsPath": "$.Items",
              "ItemSelector": {
                "MyMultiplicationFactor.$": "$.BatchInput.MyMultiplicationFactor",
                "MyItem.$": "$$.Map.Item.Value"
              }
            }
          }
        },
        "End": true,
        "Label": "Map",
        "MaxConcurrency": 1000,
        "ItemsPath": "$.MyItems",
        "ItemBatcher": {
          "MaxItemsPerBatch": 3,
          "BatchInput": {
            "MyMultiplicationFactor.$": "$.MyMultiplicationFactor"
          }
        }
      }
    }
  }
  ```

## Step 2: Create the Lambda function
<a name="itembatcher-single-item-process-config-resource"></a>

In this step, you create the Lambda function that processes each item passed from the batch.

**Important**  
Ensure that your Lambda function is under the same AWS Region as your state machine.

**To create the Lambda function**

1. Use the [Lambda console](https://console.aws.amazon.com/lambda/home) to create a **Python** Lambda function named **ProcessSingleItem**. For information about creating a Lambda function, see [Step 4: Configure the Lambda function](tutorial-map-distributed.md#use-dist-map-config-resource) in the [Getting started with using Distributed Map state](tutorial-map-distributed.md) tutorial.

1. Copy the following code for the Lambda function and paste it into the **Code source** section of your Lambda function.

   ```
   import json
   
   def lambda_handler(event, context):
       
       multiplication_factor = event['MyMultiplicationFactor']
       item = event['MyItem']
       
       result = multiplication_factor * item
       
       return {
           'statusCode': 200,
           'multiplied': result
       }
   ```

1. After you create your Lambda function, copy the function's ARN displayed in the upper-right corner of the page. The following is an example ARN, where *`function-name`* is the name of the Lambda function (in this case, `ProcessSingleItem`):

   ```
   arn:aws:lambda:region:123456789012:function:function-name
   ```

   You'll need to provide the function ARN in the state machine you created in [Step 1](#itembatcher-single-item-process-create-state-machine).

1. Choose **Deploy** to deploy the changes.

## Step 3: Run the state machine
<a name="itembatcher-param-task-run-state-machine"></a>

When you run the [state machine](#itembatcher-single-item-process-create-state-machine), the *Distributed Map state* starts four child workflow executions, where each execution processes three items, while one execution processes a single item.

The following example shows the data passed to one of the [`ProcessSingleItem`](#itembatcher-single-item-process-config-resource) function invocations inside a child workflow execution.

```
{
  "MyMultiplicationFactor": 7,
  "MyItem": 1
}
```

Given this input, the following example shows the output that is returned by the Lambda function.

```
{
  "statusCode": 200,
  "multiplied": 7
}
```

The following example shows the output JSON array for one of the child workflow executions.

```
[
  {
    "statusCode": 200,
    "multiplied": 7
  },
  {
    "statusCode": 200,
    "multiplied": 14
  },
  {
    "statusCode": 200,
    "multiplied": 21
  }
]
```

The state machine returns the following output that contains four arrays for the four child workflow executions. These arrays contain the multiplication results of the individual input items.

Finally, the state machine output is an array named `multiplied` that combines all the multiplication results returned for the four child workflow executions.

```
[
  [
    {
      "statusCode": 200,
      "multiplied": 7
    },
    {
      "statusCode": 200,
      "multiplied": 14
    },
    {
      "statusCode": 200,
      "multiplied": 21
    }
  ],
  [
    {
      "statusCode": 200,
      "multiplied": 28
    },
    {
      "statusCode": 200,
      "multiplied": 35
    },
    {
      "statusCode": 200,
      "multiplied": 42
    }
  ],
  [
    {
      "statusCode": 200,
      "multiplied": 49
    },
    {
      "statusCode": 200,
      "multiplied": 56
    },
    {
      "statusCode": 200,
      "multiplied": 63
    }
  ],
  [
    {
      "statusCode": 200,
      "multiplied": 70
    }
  ]
]
```

To combine all the multiplication results returned by the child workflow executions into a single output array, you can use the [ResultSelector](input-output-inputpath-params.md#input-output-resultselector) field. Define this field inside the *Distributed Map state* to find all the results, extract the individual results, and then combine them into a single output array named `multiplied`.

To use the `ResultSelector` field, update your state machine definition as shown in the following example.

```
{
  "StartAt": "Pass",
  "States": {
    ...
    ...
    "Map": {
      "Type": "Map",
      ...
      ...
      "ItemBatcher": {
        "MaxItemsPerBatch": 3,
        "BatchInput": {
          "MyMultiplicationFactor.$": "$.MyMultiplicationFactor"
        }
      },
      "ItemsPath": "$.MyItems",
      "ResultSelector": {
        "multiplied.$": "$..multiplied"
      }
    }
  }
}
```

The updated state machine returns a consolidated output array as shown in the following example.

```
{
  "multiplied": [7, 14, 21, 28, 35, 42, 49, 56, 63, 70]
}
```

# Starting a Step Functions workflow in response to events
<a name="tutorial-cloudwatch-events-s3"></a>

You can execute an AWS Step Functions state machine in response to an event routed by an Amazon EventBridge rule to Step Functions as a target. 

The following tutorial shows you how to configure a state machine as a target of an Amazon EventBridge rule. Whenever files are added to an Amazon Simple Storage Service (Amazon S3) bucket, the EventBridge rule will start the state machine.

A practical example of this approach could be a state machine that runs Amazon Rekognition analysis on image files added to the bucket to categorize and assign keywords.

In this tutorial, you start the execution of a `Helloworld` state machine by uploading a file to an Amazon S3 bucket. Then you review the example input of that execution to identify the information that is included in input from the Amazon S3 event notification delivered to EventBridge.

## Prerequisite: Create a State Machine
<a name="tutorial-cloudwatch-events-s3-prereqs"></a>

Before you can configure a state machine as an Amazon EventBridge target, you must create the state machine.
+ To create a basic state machine, use the [Creating state machine that uses a Lambda function](tutorial-creating-lambda-state-machine.md) tutorial.
+ If you already have a `Helloworld` state machine, proceed to the next step.

## Step 1: Create a Bucket in Amazon S3
<a name="tutorial-cloudwatch-events-s3-bucket"></a>

Now that you have a `Helloworld` state machine, you need to create an Amazon S3 bucket which stores your files. In Step 3 of this tutorial, you set up a rule so that when a file is uploaded to this bucket, EventBridge triggers an execution of your state machine.

1. Navigate to the [Amazon S3 console](https://console.aws.amazon.com/s3/), and then choose **Create bucket** to create the bucket in which you want to store your files and trigger an Amazon S3 event rule.

1. Enter a **Bucket name**, such as `username-sfn-tutorial`.
**Note**  
Bucket names must be unique across all existing bucket names in all AWS Regions in Amazon S3. Use your own *username* to make this name unique. You need to create all resources in the same AWS Region.

1. Keep all the default selections on the page, and choose **Create bucket**.

## Step 2: Enable Amazon S3 Event Notification with EventBridge
<a name="tutorial-cloudwatch-events-s3-eb-notification"></a>

After you create the Amazon S3 bucket, configure it to send events to EventBridge whenever certain events happen in your S3 bucket, such as file uploads.

1. Navigate to the [Amazon S3 console](https://console.aws.amazon.com/s3/).

1. In the **Buckets** list, choose the name of the bucket that you want to enable events for.

1. Choose **Properties**.

1. Scroll down the page to view the **Event Notifications** section, and then choose **Edit** in the **Amazon EventBridge** subsection.

1. Under **Send notifications to Amazon EventBridge for all events in this bucket**, choose **On**.

1. Choose **Save changes**.
**Note**  
After you enable EventBridge, it takes around five minutes for the changes to take effect.

## Step 3: Create an Amazon EventBridge Rule
<a name="tutorial-cloudwatch-events-s3-cwe"></a>

After you have a state machine, and have created the Amazon S3 bucket and configured it to send event notifications to EventBridge, create an EventBridge rule.

**Note**  
You must configure EventBridge rule in the same AWS Region as the Amazon S3 bucket.

### To create the rule
<a name="tutorial-cloudwatch-events-s3-create-rule"></a>

1. Navigate to the [Amazon EventBridge console](https://console.aws.amazon.com/events/), choose **Create rule**.
**Tip**  
Alternatively, in the navigation pane on the EventBridge console, choose **Rules** under **Buses**, and then choose **Create rule**.

1. Enter a **Name** for your rule (for example, `S3Step Functions`) and optionally enter a **Description** for the rule.

1. For **Event bus** and **Rule type**, keep the default selections.

1. Choose **Next**. This opens the **Build event pattern** page.

1. Scroll down to the **Event pattern** section, and do the following:

   1. For **Event source**, keep the default selection of **AWS events or EventBridge partner events**.

   1. For **AWS service**, choose **Simple Storage Service (S3)**.

   1. For **Event type**, choose **Amazon S3 Event Notification**.

   1. Choose **Specific event(s)**, and then choose **Object Created**.

   1. Choose **Specific bucket(s) by name** and enter the bucket name you created in [Step 1](#tutorial-cloudwatch-events-s3-bucket) (`username-sfn-tutorial`) to store your files.

   1. Choose **Next**. This opens the **Select target(s)** page.

### To create the target
<a name="tutorial-cloudwatch-events-s3-create-rule2"></a>

1. In **Target 1**, keep the default selection of **AWS service**.

1. In the **Select a target** dropdown list, select **Step Functions state machine**.

1. In the **State machine** list, select the state machine that you [created earlier](#tutorial-cloudwatch-events-s3-prereqs) (for example, `Helloworld`).

1. Keep all the default selections on the page, and choose **Next**. This opens the **Configure tags** page.

1. Choose **Next** again. This opens the **Review and create** page.

1. Review the details of the rule and choose **Create rule**.

   The rule is created and the **Rules** page is displayed, listing all your Amazon EventBridge rules.

## Step 4: Test the Rule
<a name="tutorial-cloudwatch-events-test-rule"></a>

Now that everything is in place, test adding a file to the Amazon S3 bucket, and then look at the input of the resulting state machine execution.

1. Add a file to your Amazon S3 bucket.

   Navigate to the [Amazon S3 console](https://console.aws.amazon.com/s3/), choose the bucket you created to store files (`username-sfn-tutorial`), and then choose **Upload**.

1. Add a file, for example `test.png`, and then choose **Upload**.

   This launches an execution of your state machine, passing information from AWS CloudTrail as the input.

1. Check the execution for your state machine.

   Navigate to the [Step Functions console and select the state machine used in your Amazon EventBridge rule (`Helloworld`)](https://console.aws.amazon.com/states/).

1. Select the most recent execution of that state machine and expand the **Execution Input** section.

   This input includes information such as the bucket name and the object name. In a real-world use case, a state machine can use this input to perform actions on that object.

## Example of Execution Input
<a name="tutorial-cloudwatch-events-example"></a>

The following example shows a typical input to the state machine execution.

```
{
    "version": "0",
    "id": "6c540ad4-0671-9974-6511-756fbd7771c3",
    "detail-type": "Object Created",
    "source": "aws.s3",
    "account": "123456789012",
    "time": "2023-06-23T23:45:48Z",
    "region": "us-east-2",
    "resources": [
      "arn:aws:s3:::username-sfn-tutorial"
    ],
    "detail": {
      "version": "0",
      "bucket": {
        "name": "username-sfn-tutorial"
      },
      "object": {
        "key": "test.png",
        "size": 800704,
        "etag": "f31d8546bb67845b4d3048cde533b937",
        "sequencer": "00621049BA9A8C712B"
      },
      "request-id": "79104EXAMPLEB723",
      "requester": "123456789012",
      "source-ip-address": "200.0.100.11",
      "reason": "PutObject"
    }
  }
```

# Creating a Step Functions API using API Gateway
<a name="tutorial-api-gateway"></a>

You can use Amazon API Gateway to associate your AWS Step Functions APIs with methods in an API Gateway API. When an HTTPS request is sent to an API method, API Gateway invokes your Step Functions API actions.

This tutorial shows you how to create an API that uses one resource and the `POST` method to communicate with the `[StartExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html)` API action. You'll use the AWS Identity and Access Management (IAM) console to create a role for API Gateway. Then, you'll use the API Gateway console to create an API Gateway API, create a resource and method, and map the method to the `StartExecution` API action. Finally, you'll deploy and test your API.

**Note**  
Although Amazon API Gateway can start a Step Functions execution by calling `StartExecution`, you must call `[DescribeExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_DescribeExecution.html)` to get the result.

## Step 1: Create an IAM Role for API Gateway
<a name="api-gateway-step-1"></a>

Before you create your API Gateway API, you need to give API Gateway permission to call Step Functions API actions.<a name="api-gateway-procedure-create-iam-role"></a>

**To set up permissions for API Gateway**

1. Sign in to the [IAM console](https://console.aws.amazon.com/iam/home) and choose **Roles**, **Create role**.

1. On the **Select trusted entity** page, do the following:

   1. For **Trusted entity type**, keep the default selection of **AWS service**.

   1. For **Use case**, choose **API Gateway** from the dropdown list.

1. Select **API Gateway**, and then choose **Next**.

1. On the **Add permissions** page, choose **Next**.

1. (Optional) On the **Name, review, and create** page, enter details, such as the role name. For example, enter **APIGatewayToStepFunctions**.

1. Choose **Create role**.

   The IAM role appears in the list of roles.

1. Choose the name of your role and note the **Role ARN**, as shown in the following example.

   ```
   arn:aws:iam::123456789012:role/APIGatewayToStepFunctions
   ```<a name="api-gateway-attach-policy-to-role"></a>

**To attach a policy to the IAM role**

1. On the **Roles** page, search for your role (`APIGatewayToStepFunctions`), and then choose the role.

1. On the **Permissions** tab, choose **Add permissions**, and then choose **Attach policies**.

1. On the **Attach Policy** page, search for `AWSStepFunctionsFullAccess`, choose the policy, and then choose **Add permissions**.

## Step 2: Create your API Gateway API
<a name="api-gateway-step-2"></a>

After you create your IAM role, you can create your custom API Gateway API.

**To create the API**

1. Open the [Amazon API Gateway console](https://console.aws.amazon.com/apigateway/), and then choose **Create API**.

1. On the **Choose an API type** page, in the **REST API** pane, choose **Build**.

1. On the **Create REST API** page, select **New API**, and then enter ***StartExecutionAPI*** for the **API name**.

1. Keep **API endpoint type** as **Regional**, and then choose **Create API**.<a name="api-gateway-create-resource"></a>

**To create a resource**

1. On the **Resources** page of ***StartExecutionAPI***, choose **Create resource**.

1. On the **Create resource** page, enter **execution** for **Resource name**, and then choose **Create resource**.<a name="api-gateway-create-method"></a>

**To create a POST method**

1. Choose the **/execution** resource, and then choose **Create method**.

1. For **Method type**, choose `POST`.

1. For **Integration type**, choose **AWS service**.

1. For **AWS Region**, choose a Region from the list.

1. For **AWS service**, choose **Step Functions** from the list.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST** from the list.
**Note**  
All Step Functions API actions use the HTTP `POST` method.

1. For **Action type**, select **Use action name**.

1. For **Action name**, enter **StartExecution**.

1. For **Execution role**, enter [the role ARN of the IAM role that you created earlier](#api-gateway-procedure-create-iam-role), as shown in the following example.

   ```
   arn:aws:iam::123456789012:role/APIGatewayToStepFunctions
   ```

1. Keep the default options for **Credential cache** and **Default timeout**, and then choose **Save**.

The visual mapping between API Gateway and Step Functions is displayed on the **/execution - POST - Method execution** page.

## Step 3: Test and Deploy the API Gateway API
<a name="api-gateway-step-3"></a>

Once you have created the API, test and deploy it. <a name="api-gateway-test-api"></a>

**To test the communication between API Gateway and Step Functions**

1. On the **/execution - POST - Method Execution** page, choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. On the **/execution - POST - Method Test** tab, copy the following request parameters into the **Request body** section using the ARN of an existing state machine (or [create a new state machine that uses a Lambda function](tutorial-creating-lambda-state-machine.md)), and then choose **Test**.

   ```
   {
      "input": "{}",
      "name": "MyExecution",
      "stateMachineArn": "arn:aws:states:region:123456789012:stateMachine:HelloWorld"
   }
   ```

   For more information, see the `StartExecution` [Request Syntax](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html#API_StartExecution_RequestSyntax) in the *AWS Step Functions API Reference*.
**Note**  
If you don't want to include the ARN of your state machine in the body of your API Gateway call, you can configure a mapping template in the **Integration request** tab, as shown in the following example.  

   ```
   {
       "input": "$util.escapeJavaScript($input.json('$'))",
       "stateMachineArn": "$util.escapeJavaScript($stageVariables.arn)"
   }
   ```
With this approach, you can specify ARNs of different state machines based on your development stage (for example, `dev`, `test`, and `prod`). For more information about specifying stage variables in a mapping template, see [https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#stagevariables-template-reference](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#stagevariables-template-reference) in the *API Gateway Developer Guide*.

1. The execution starts and the execution ARN and its epoch date are displayed under **Response body**.

   ```
   {
      "executionArn": "arn:aws:states:region:123456789012:execution:HelloWorld:MyExecution",
      "startDate": 1486768956.878
   }
   ```
**Note**  
You can view the execution by choosing your state machine on the [AWS Step Functions console](https://console.aws.amazon.com/states/).

**To deploy your API**

1. On the **Resources** page of ***StartExecutionAPI***, choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **alpha**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

**To test your deployment**

1. On the **Stages** page of ***StartExecutionAPI***, expand **alpha**, **/**, **/execution**, **POST**, and then choose the **POST** method.

1. Under **Method overrides**, choose the copy icon to copy your API's invoke URL. The full URL should look like the following example.

   ```
   https://a1b2c3d4e5.execute-api.region.amazonaws.com/alpha/execution
   ```

1. From the command line, run the `curl` command using the ARN of your state machine, and then invoke the URL of your deployment, as shown in the following example.

   ```
   curl -X POST -d '{"input": "{}","name": "MyExecution","stateMachineArn": "arn:aws:states:region:123456789012:stateMachine:HelloWorld"}' https://a1b2c3d4e5.execute-api.region.amazonaws.com/alpha/execution
   ```

   The execution ARN and its epoch date are returned, as shown in the following example.

   ```
   {"executionArn":"arn:aws:states:region:123456789012:execution:HelloWorld:MyExecution","startDate":1.486772644911E9}
   ```
**Note**  
If you get a "Missing Authentication Token" error, make sure that the invoke URL ends with **/execution**.

# Creating an Activity state machine using Step Functions
<a name="tutorial-creating-activity-state-machine"></a>

This tutorial shows you how to create an activity-based state machine using Java and AWS Step Functions. Activities allow you to control worker code that runs somewhere else from your state machine. For an overview, see [Learn about Activities in Step Functions](concepts-activities.md) in [Learn about state machines in Step Functions](concepts-statemachines.md). 

To complete this tutorial, you need the following:
+ The [SDK for Java](https://aws.amazon.com/sdk-for-java/). The example activity in this tutorial is a Java application that uses the AWS SDK for Java to communicate with AWS.
+ AWS credentials in the environment or in the standard AWS configuration file. For more information, see [Set Up Your AWS Credentials](https://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/set-up-creds.html) in the *AWS SDK for Java Developer Guide*.

## Step 1: Create an Activity
<a name="create-activity-state-machine-step-1"></a>

You must make Step Functions aware of the *activity* whose *worker* (a program) you want to create. Step Functions responds with an Amazon Resource Name(ARN) that establishes an identity for the activity. Use this identity to coordinate the information passed between your state machine and worker.

**Important**  
Ensure that your activity task is under the same AWS account as your state machine.

1. In the [Step Functions console](https://console.aws.amazon.com/states/home), in the navigation pane on the left, choose **Activities**.

1. Choose **Create activity**.

1. Enter a **Name** for the activity, for example, `get-greeting`, and then choose **Create activity**.

1. When your activity task is created, make a note of its ARN, as shown in the following example.

   ```
   arn:aws:states:region:123456789012:activity:get-greeting
   ```

## Step 2: Create a state machine
<a name="create-activity-state-machine-step-2"></a>

Create a state machine that determines when your activity is invoked and when your worker should perform its primary work, collect its results, and return them. To create the state machine, you'll use the [Code editor](workflow-studio.md#wfs-interface-code-editor) of Workflow Studio.

1. In the [Step Functions console](https://console.aws.amazon.com/states/home), in the navigation pane on the left, choose **State machines**.

1. On the **State machines** page, choose **Create state machine**.

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. For this tutorial, you'll write the [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition of your state machine in the code editor. To do this, choose **Code**.

1. Remove the existing boilerplate code and paste the following code. Remember to replace the example ARN in the `Resource` field with the ARN of the activity task that you created earlier in [Step 1: Create an Activity](#create-activity-state-machine-step-1).

   ```
   {
     "Comment": "An example using a Task state.",
     "StartAt": "getGreeting",
     "Version": "1.0",
     "TimeoutSeconds": 300,
     "States":
     {
       "getGreeting": {
         "Type": "Task",
         "Resource": "arn:aws:states:region:123456789012:activity:get-greeting",
         "End": true
       }
     }
   }
   ```

   This is a description of your state machine using the [Amazon States Language](concepts-amazon-states-language.md) (ASL). It defines a single `Task` state named `getGreeting`. For more information, see [State Machine Structure](statemachine-structure.md).

1. On the [Graph visualization](workflow-studio.md#wfs-interface-code-graph-viz), make sure the workflow graph for the ASL definition you added looks similar to the following graph.  
![\[Graph visualization of state machine with RunActivity task state.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-create-state-machine-custom-preview.png)

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **ActivityStateMachine**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, keep all the default selections in **State machine settings**.

   If you've [previously created an IAM role](procedure-create-iam-role.md) with the correct permissions for your state machine and want to use it, in **Permissions**, select **Choose an existing role**, and then select a role from the list. Or select **Enter a role ARN** and then provide an ARN for that IAM role.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

## Step 3: Implement a Worker
<a name="create-activity-state-machine-step-3"></a>

Create a *worker*. A worker is a program that is responsible for:
+ Polling Step Functions for activities using the `GetActivityTask` API action.
+ Performing the work of the activity using your code, (for example, the `getGreeting()` method in the following code).
+ Returning the results using the `SendTaskSuccess`, `SendTaskFailure`, and `SendTaskHeartbeat` API actions.

**Note**  
For a more complete example of an activity worker, see [Example: Activity Worker in Ruby](concepts-activities.md#example-ruby-activity-worker). This example provides an implementation based on best practices, which you can use as a reference for your activity worker. The code implements a consumer-producer pattern with a configurable number of threads for pollers and activity workers. 

### To implement the worker
<a name="create-activity-state-machine-implement-worker"></a>

1. Create a file named `GreeterActivities.java`.

1. Add the following code to it.

   ```
   import com.amazonaws.ClientConfiguration;
   import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;
   import com.amazonaws.regions.Regions;
   import com.amazonaws.services.stepfunctions.AWSStepFunctions;
   import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder;
   import com.amazonaws.services.stepfunctions.model.GetActivityTaskRequest;
   import com.amazonaws.services.stepfunctions.model.GetActivityTaskResult;
   import com.amazonaws.services.stepfunctions.model.SendTaskFailureRequest;
   import com.amazonaws.services.stepfunctions.model.SendTaskSuccessRequest;
   import com.amazonaws.util.json.Jackson;
   import com.fasterxml.jackson.databind.JsonNode;
   import java.util.concurrent.TimeUnit;
   
   
   public class GreeterActivities {
   
       public String getGreeting(String who) throws Exception {
           return "{\"Hello\": \"" + who + "\"}";
       }
   
       public static void main(final String[] args) throws Exception {
           GreeterActivities greeterActivities = new GreeterActivities();
           ClientConfiguration clientConfiguration = new ClientConfiguration();
           clientConfiguration.setSocketTimeout((int)TimeUnit.SECONDS.toMillis(70));
   
           AWSStepFunctions client = AWSStepFunctionsClientBuilder.standard()
                   .withRegion(Regions.US_EAST_1)
                   .withCredentials(new EnvironmentVariableCredentialsProvider())
                   .withClientConfiguration(clientConfiguration)
                   .build();
   
           while (true) {
               GetActivityTaskResult getActivityTaskResult =
                       client.getActivityTask(
                               new GetActivityTaskRequest().withActivityArn(ACTIVITY_ARN));
   
               if (getActivityTaskResult.getTaskToken() != null) {
                   try {
                       JsonNode json = Jackson.jsonNodeOf(getActivityTaskResult.getInput());
                       String greetingResult =
                               greeterActivities.getGreeting(json.get("who").textValue());
                       client.sendTaskSuccess(
                               new SendTaskSuccessRequest().withOutput(
                                       greetingResult).withTaskToken(getActivityTaskResult.getTaskToken()));
                   } catch (Exception e) {
                       client.sendTaskFailure(new SendTaskFailureRequest().withTaskToken(
                               getActivityTaskResult.getTaskToken()));
                   }
               } else {
                   Thread.sleep(1000);
               }
           }
       }
   }
   ```
**Note**  
The `EnvironmentVariableCredentialsProvider` class in this example assumes that the `AWS_ACCESS_KEY_ID` (or `AWS_ACCESS_KEY`) and `AWS_SECRET_KEY` (or `AWS_SECRET_ACCESS_KEY`) environment variables are set. For more information about providing the required credentials to the factory, see [AWSCredentialsProvider](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AWSCredentialsProvider.html) in the *AWS SDK for Java API Reference* and [Set Up AWS Credentials and Region for Development](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html) in the *AWS SDK for Java Developer Guide*.  
By default the AWS SDK will wait up to 50 seconds to receive data from the server for any operation. The `GetActivityTask` operation is a long-poll operation that will wait up to 60 seconds for the next available task. To prevent receiving a `SocketTimeoutException` error, set SocketTimeout to 70 seconds.

1. In the parameter list of the `GetActivityTaskRequest().withActivityArn()` constructor, replace the `ACTIVITY_ARN` value with the ARN of the activity task that you created earlier in [Step 1: Create an Activity](#create-activity-state-machine-step-1).

## Step 4: Run the state machine
<a name="create-activity-state-machine-step-4"></a>

When you start the execution of the state machine, your worker polls Step Functions for activities, performs its work (using the input that you provide), and returns its results.

1. On the ***ActivityStateMachine*** page, choose **Start execution**.

   The **Start execution** dialog box is displayed.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. In the **Input** box, enter the following JSON input to run your workflow.

      ```
      {
        "who": "AWS Step Functions"
      }
      ```

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

## Step 5: Run and Stop the Worker
<a name="create-activity-state-machine-step-5"></a>

To have the worker poll your state machine for activities, you must run the worker.

1. On the command line, navigate to the directory in which you created `GreeterActivities.java`.

1. To use the AWS SDK, add the full path of the `lib` and `third-party` directories to the dependencies of your build file and to your Java `CLASSPATH`. For more information, see [Downloading and Extracting the SDK](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-install.html#download-and-extract-sdk) in the *AWS SDK for Java Developer Guide*.

1. Compile the file.

   ```
   $ javac GreeterActivities.java
   ```

1. Run the file.

   ```
   $ java GreeterActivities
   ```

1. On the [Step Functions console](https://console.aws.amazon.com/states/home?region=us-east-1#/), navigate to the *Execution Details* page.

1. When the execution completes, examine the results of your execution.

1. Stop the worker.

# View X-Ray traces in Step Functions
<a name="tutorial-xray-traces"></a>

In this tutorial, you will learn how to use X-Ray to trace errors that occur when running a state machine. You can use [AWS X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html) to visualize the components of your state machine, identify performance bottlenecks, and troubleshoot requests that resulted in an error. In this tutorial, you will create several Lambda functions that randomly produce errors, which you can then trace and analyze using X-Ray.

The [Creating a Step Functions state machine that uses Lambda](tutorial-creating-lambda-state-machine.md) tutorial walks you though creating a state machine that calls a Lambda function. If you have completed that tutorial, skip to [Step 2](#create-xray-lambda-state-machine-step-4) and use the AWS Identity and Access Management (IAM) role that you previously created.

## Step 1: Create an IAM role for Lambda
<a name="create-xray-lambda-state-machine-step-1"></a>

Both AWS Lambda and AWS Step Functions can run code and access AWS resources (for example, data stored in Amazon S3 buckets). To maintain security, you must grant Lambda and Step Functions access to these resources.

Lambda requires you to assign an AWS Identity and Access Management (IAM) role when you create a Lambda function, in the same way Step Functions requires you to assign an IAM role when you create a state machine.

### To create a role for use with Lambda
<a name="create-xray-lambda-state-machine-to-create-a-role-for-use-with-lambda"></a>

You use the IAM console to create a service-linked role.

**To create a role (console)**

1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the navigation pane of the IAM console, choose **Roles**. Then choose **Create role**.

1. Choose the **AWS Service** role type, and then choose **Lambda**.

1. Choose the **Lambda** use case. Use cases are defined by the service to include the trust policy required by the service. Then choose **Next: Permissions**.

1. Choose one or more permissions policies to attach to the role (for example, `AWSLambdaBasicExecutionRole`). See [AWS Lambda Permissions Model](https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html).

    Select the box next to the policy that assigns the permissions that you want the role to have, and then choose **Next: Review**.

1. Enter a **Role name**.

1. (Optional) For **Role description**, edit the description for the new service-linked role.

1. Review the role, and then choose **Create role**.

## Step 2: Create a Lambda function
<a name="create-xray-lambda-state-machine-step-2"></a>

Your Lambda function will randomly throw errors or time out, producing example data to view in X-Ray.

**Important**  
Ensure that your Lambda function is under the same AWS account and AWS Region as your state machine.

1. Open the [Lambda console](https://console.aws.amazon.com/lambda/home) and choose **Create function**.

1. In the **Create function** section, choose **Author from scratch**.

1. In the **Basic information** section, configure your Lambda function:

   1. For **Function name**, enter `TestFunction1`.

   1. For **Runtime**, choose **Node.js 18.x**.

   1. For **Role**, select **Choose an existing role**.

   1. For **Existing role**, select [the Lambda role that you created earlier](#create-xray-lambda-state-machine-to-create-a-role-for-use-with-lambda).
**Note**  
If the IAM role that you created doesn't appear in the list, the role might still need a few minutes to propagate to Lambda.

   1. Choose **Create function**.

      When your Lambda function is created, note its Amazon Resource Name (ARN) in the upper-right corner of the page. For example:

      ```
      arn:aws:lambda:region:123456789012:function:TestFunction1
      ```

1. Copy the following code for the Lambda function into the **Function code** section of the ***TestFunction1*** page.

   ```
   function getRandomSeconds(max) {
       return Math.floor(Math.random() * Math.floor(max)) * 1000;
   }
   function sleep(ms) {
       return new Promise(resolve => setTimeout(resolve, ms));
   }
   export const handler = async (event) => {
       if(getRandomSeconds(4) === 0) {
           throw new Error("Something went wrong!");
       }   
       let wait_time = getRandomSeconds(5);
       await sleep(wait_time);
       return { 'response': true }
   };
   ```

   This code creates randomly timed failures, which will be used to generate example errors in your state machine that can be viewed and analyzed using X-Ray traces.

1. Choose **Save**.

## Step 3: Create two more Lambda functions
<a name="create-xray-lambda-state-machine-step-3"></a>

Create two more Lambda functions.

1. Repeat Step 2 to create two more Lambda functions. For the next function, in **Function name**, enter `TestFunction2`. For the last function, in **Function name**, enter `TestFunction3`.

1. In the Lambda console, check that you now have three Lambda functions, `TestFunction1`, `TestFunction2`, and `TestFunction3`.

## Step 4: Create a state machine
<a name="create-xray-lambda-state-machine-step-4"></a>

In this step, you'll use the [Step Functions console](https://console.aws.amazon.com/states/home?region=us-east-1#/) to create a state machine with three `Task` states. Each `Task` state will a reference one of your three Lambda functions. 

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.
**Important**  
Make sure that your state machine is under the same AWS account and Region as the Lambda functions you created earlier in [Step 2](#create-xray-lambda-state-machine-step-2) and [Step 3](#create-xray-lambda-state-machine-step-3).

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. For this tutorial, you'll write the [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition of your state machine in the [Code editor](workflow-studio.md#wfs-interface-code-editor). To do this, choose **Code**.

1. Remove the existing boilerplate code and paste the following code. In the Task state definition, remember to replace the example ARNs with the ARNs of the Lambda functions you created.

   ```
   {
     "StartAt": "CallTestFunction1",
     "States": {
       "CallTestFunction1": {
         "Type": "Task",
         "Resource": "arn:aws:lambda:region:123456789012:function:test-function1",
         "Catch": [
           {
             "ErrorEquals": [
               "States.TaskFailed"
             ],
             "Next": "AfterTaskFailed"
           }
         ],
         "Next": "CallTestFunction2"
       },
       "CallTestFunction2": {
         "Type": "Task",
         "Resource": "arn:aws:lambda:region:123456789012:function:test-function2",
         "Catch": [
           {
             "ErrorEquals": [
               "States.TaskFailed"
             ],
             "Next": "AfterTaskFailed"
           }
         ],
         "Next": "CallTestFunction3"
       },
       "CallTestFunction3": {
         "Type": "Task",
         "Resource": "arn:aws:lambda:region:123456789012:function:test-function3",
         "TimeoutSeconds": 5,
         "Catch": [
           {
             "ErrorEquals": [
               "States.Timeout"
             ],
             "Next": "AfterTimeout"
           },
           {
             "ErrorEquals": [
               "States.TaskFailed"
             ],
             "Next": "AfterTaskFailed"
           }
         ],
         "Next": "Succeed"
       },
       "Succeed": {
         "Type": "Succeed"
       },
       "AfterTimeout": {
         "Type": "Fail"
       },
       "AfterTaskFailed": {
         "Type": "Fail"
       }
     }
   }
   ```

   This is a description of your state machine using the Amazon States Language. It defines three `Task` states named `CallTestFunction1`, `CallTestFunction2` and `CallTestFunction3`. Each calls one of your three Lambda functions. For more information, see [State Machine Structure](statemachine-structure.md).

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **TraceFunctions**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, under **Additional configuration**, choose **Enable X-Ray tracing**. Keep all the other default selections in **State machine settings**.

   If you've [previously created an IAM role](procedure-create-iam-role.md) with the correct permissions for your state machine and want to use it, in **Permissions**, select **Choose an existing role**, and then select a role from the list. Or select **Enter a role ARN** and then provide an ARN for that IAM role.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

## Step 5: Run the state machine
<a name="create-xray-lambda-state-machine-step-5"></a>

State machine executions are instances where you run your workflow to perform tasks.

1. On the ***TraceFunctions*** page, choose **Start execution**.

   The **New execution** page is displayed.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

      Run several (at least three) executions.

1. After the executions have finished, follow the **X-Ray trace map** link. You can view the trace while an execution is still running, but you may want to see the execution results before viewing the X-Ray trace map.

1. View the service map to identify where errors are occurring, connections with high latency, or traces for requests that were unsuccessful. In this example, you can see how much traffic each function is receiving. `TestFunction2` was called more often than `TestFunction3`, and `TestFunction1` was called more than twice as often as `TestFunction2`.

   The service map indicates the health of each node by coloring it based on the ratio of successful calls to errors and faults:
   +  **Green** for successful calls 
   +  **Red** for server faults (500 series errors) 
   +  **Yellow** for client errors (400 series errors) 
   +  **Purple** for throttling errors (429 Too Many Requests)   
![\[Illustrative example screenshot of X-Ray trace nodes for three test functions.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-xray-service.png)

   You can also choose a service node to view requests for that node, or an edge between two nodes to view requests that traveled that connection. 

1. View the X-Ray trace map to see what has happened for each execution. The Timeline view shows a hierarchy of segments and subsegments. The first entry in the list is the segment, which represents all data recorded by the service for a single request. Below the segment are subsegments. This example shows subsegments recorded by the Lambda functions.  
![\[Illustrative example screenshot of X-Ray timeline segments and subsegments for test functions.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/tutorial-xray-trace.png)

   For more information on understanding X-Ray traces and using X-Ray with Step Functions, see the [Trace Step Functions request data in AWS X-Ray](concepts-xray-tracing.md) 

# Gather Amazon S3 bucket info using AWS SDK service integrations
<a name="tutorial-gather-s3-info"></a>

This tutorial shows you how to perform an [AWS SDK integration](supported-services-awssdk.md) with Amazon Simple Storage Service. The state machine you create in this tutorial gathers information about your Amazon S3 buckets, then list your buckets along with version information for each bucket in the current region. 

## Step 1: Create the state machine
<a name="aws-sdk-create-state-machine"></a>

Using the Step Functions console, you'll create a state machine that includes a `Task` state to list all the Amazon S3 buckets in the current account and region. Then, you'll add another `Task` state that invokes the `[HeadBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html)` API to verify if the returned bucket is accessible in the current region. If the bucket isn't accessible, the `HeadBucket` API call returns the `S3.S3Exception` error. You'll include a `Catch` block to catch this exception and a `Pass` state as the fallback state.

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. For this tutorial, you'll write the [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition of your state machine in the [Code editor](workflow-studio.md#wfs-interface-code-editor). To do this, choose **Code**.

1. Remove the existing boilerplate code and paste the following state machine definition.

   ```
   {
     "Comment": "A description of my state machine",
     "StartAt": "ListBuckets",
     "States": {
       "ListBuckets": {
         "Type": "Task",
         "Parameters": {},
         "Resource": "arn:aws:states:::aws-sdk:s3:listBuckets",
         "Next": "Map"
       },
       "Map": {
         "Type": "Map",
         "ItemsPath": "$.Buckets",
         "ItemProcessor": {
           "ProcessorConfig": {
             "Mode": "INLINE"
           },
           "StartAt": "HeadBucket",
           "States": {
             "HeadBucket": {
               "Type": "Task",
               "ResultPath": null,
               "Parameters": {
                 "Bucket.$": "$.Name"
               },
               "Resource": "arn:aws:states:::aws-sdk:s3:headBucket",
               "Catch": [
                 {
                   "ErrorEquals": [
                     "S3.S3Exception"
                   ],
                   "ResultPath": null,
                   "Next": "Pass"
                 }
               ],
               "Next": "GetBucketVersioning"
             },
             "GetBucketVersioning": {
               "Type": "Task",
               "End": true,
               "Parameters": {
                 "Bucket.$": "$.Name"
               },
               "ResultPath": "$.BucketVersioningInfo",
               "Resource": "arn:aws:states:::aws-sdk:s3:getBucketVersioning"
             },
             "Pass": {
               "Type": "Pass",
               "End": true,
               "Result": {
                 "Status": "Unknown"
               },
               "ResultPath": "$.BucketVersioningInfo"
             }
           }
         },
         "End": true
       }
     }
   }
   ```

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **Gather-S3-Bucket-Info-Standard**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   Keep all the default selections in **State machine settings**.

   If you've [previously created an IAM role](procedure-create-iam-role.md) with the correct permissions for your state machine and want to use it, in **Permissions**, select **Choose an existing role**, and then select a role from the list. Or select **Enter a role ARN** and then provide an ARN for that IAM role.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

   In [Step 2](#aws-sdk-add-iam-permissions), you'll add the missing permissions to the state machine role.

## Step 2: Add the necessary IAM role permissions
<a name="aws-sdk-add-iam-permissions"></a>

To gather information about the Amazon S3 buckets in your current region, you must provide your state machine the necessary permissions to access the Amazon S3 buckets.

1. On the state machine page, choose **IAM role ARN** to open the **Roles** page for the state machine role.

1. Choose **Add permissions** and then choose **Create inline policy.**

1. Choose the **JSON** tab, and then paste the following permissions into the JSON editor.  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "VisualEditor0",
               "Effect": "Allow",
               "Action": [
                   "s3:ListAllMyBuckets",
                   "s3:ListBucket",
                   "s3:GetBucketVersioning"
               ],
               "Resource": "*"
           }
       ]
   }
   ```

1. Choose **Review policy**.

1. Under **Review policy**, for the policy **Name**, enter **s3-bucket-permissions**.

1. Choose **Create policy**.

## Step 3: Run a Standard state machine execution
<a name="aws-sdk-run-standard"></a>

1. On the **Gather-S3-Bucket-Info-Standard** page, choose **Start execution**.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

## Step 4: Run an Express state machine execution
<a name="aws-sdk-run-express"></a>

1. Create an Express state machine using the state machine definition provided in [Step 1](#aws-sdk-create-state-machine). Make sure that you also include the necessary IAM role permissions as explained in [Step 2](#aws-sdk-add-iam-permissions).
**Tip**  
To distinguish from the Standard machine you created earlier, name the Express state machine as **Gather-S3-Bucket-Info-Express**.

1. On the **Gather-S3-Bucket-Info-Standard** page, choose **Start execution**.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

# Continue long-running workflows using Step Functions API (recommended)
<a name="tutorial-continue-new"></a>

AWS Step Functions is designed to run workflows with a finite duration and number of steps. Standard workflow executions have a maximum duration of one year and 25,000 events (see [Step Functions service quotas](service-quotas.md)).

For long-running executions, you can avoid reaching the hard quota by starting a new workflow execution from the `Task` state. You need to break your workflows up into smaller state machines which continue ongoing work in a new execution.

To start new workflow executions, you will call the `StartExecution` API action from your `Task` state and pass the necessary parameters.

Step Functions can start workflow executions by calling its own API as an [integrated service](integrate-services.md). We recommend that you use this approach to avoid exceeding service quotas for long-running executions.

## Step 1: Create a long-running state machine
<a name="use-sfn-api-create-called-state-machine"></a>

Create a long-running state machine that you want to start from the `Task` state of a different state machine. For this tutorial, use the [state machine that uses a Lambda function](tutorial-creating-lambda-state-machine.md).

**Note**  
Make sure to copy the name and Amazon Resource Name of this state machine in a text file for later use.

## Step 2: Create a state machine to call the Step Functions API action
<a name="use-sfn-api-create-caller-state-machine"></a>

**To start workflow executions from a `Task` state**

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. From the **Actions** tab, drag the **StartExecution** API action and drop it on the empty state labelled **Drag first state here**.

1. Choose the **StartExecution** state and do the following in the **Configuration** tab in [Design mode](workflow-studio.md#wfs-interface-design-mode):

   1. Rename the state to **Start nested execution**.

   1. For **Integration type**, choose **AWS SDK - new** from the dropdown list.

   1. In **API Parameters**, do the following:

      1. For `StateMachineArn`, replace the sample Amazon Resource Name with the ARN of your state machine. For example, enter the ARN of the [state machine that uses Lambda](tutorial-creating-lambda-state-machine.md).

      1. For `Input` node, replace the existing placeholder text with the following value:

         ```
         "Comment": "Starting workflow execution using a Step Functions API action"
         ```

      1. Make sure your inputs in **API Parameters** look similar to the following:

         ```
         {
           "StateMachineArn": "arn:aws:states:us-east-2:123456789012:stateMachine:LambdaStateMachine",
           "Input": {
             "Comment": "Starting workflow execution using a Step Functions API action",
             "AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$": "$$.Execution.Id"
           }
         ```

1. (Optional) Choose **Definition** on the [Inspector panel](workflow-studio.md#workflow-studio-components-formdefinition) panel to view the automatically-generated [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition of your workflow.
**Tip**  
You can also view the ASL definition in the [Code editor](workflow-studio.md#wfs-interface-code-editor) of Workflow Studio. In the code editor, you can also edit the ASL definition of your workflow.

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **ParentStateMachine**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, keep all the default selections in **State machine settings**.

   If you've [previously created an IAM role](procedure-create-iam-role.md) with the correct permissions for your state machine and want to use it, in **Permissions**, select **Choose an existing role**, and then select a role from the list. Or select **Enter a role ARN** and then provide an ARN for that IAM role.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

## Step 3: Update the IAM policy
<a name="use-sfn-api-update-policy-start-execution"></a>

To make sure your state machine has permissions to start the execution of the [state machine that uses a Lambda function](tutorial-creating-lambda-state-machine.md), you need to attach an inline policy to your state machine's IAM role. For more information, see [Embedding Inline Policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#embed-inline-policy-console) in the *IAM User Guide*.

1. On the **ParentStateMachine** page, choose the **IAM role ARN** to navigate to the IAM **Roles** page for your state machine.

1. Assign an appropriate permission to the IAM role of the **ParentStateMachine** for it to be able to start execution of another state machine. To assign the permission, do the following:

   1. On the IAM **Roles** page, choose **Add permissions**, and then choose **Create inline policy**.

   1. On the **Create policy** page, choose the **JSON** tab.

   1. Replace the existing text with the following policy.  
****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "states:StartExecution"
                ],
                "Resource": [
                    "arn:aws:states:us-east-1:123456789012:stateMachine:LambdaStateMachine"
                ]
            }
        ]
      }
      ```

   1. Choose **Review policy**.

   1. Specify a name for the policy, and then choose **Create policy**.

## Step 4: Run the state machine
<a name="use-sfn-api-start-execution"></a>

State machine executions are instances where you run your workflow to perform tasks.

1. On the **ParentStateMachine** page, choose **Start execution**.

   The **Start execution** dialog box is displayed.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. (Optional) In the **Input** box, enter input values in JSON format to run your workflow.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

1. Open the **LambdaStateMachine** page and notice a new execution triggered by the **ParentStateMachine**.

# Using a Lambda function to continue a new execution in Step Functions
<a name="tutorial-use-lambda-cont-exec"></a>

**Tip**  
The following approach uses a Lambda function to start a new workflow execution. We **recommend** using a Step Functions Task state to start new workflow executions. See how in the following tutorial: ** [Continue long-running workflows using Step Functions API (recommended)](tutorial-continue-new.md) **.

You can create a state machine that uses a Lambda function to start a new execution before the current execution terminates. With this approach to continue ongoing work in a new execution, you can break large jobs into smaller workflows, or run a workflow indefinitely.

This tutorial builds on the concept of using an external Lambda function to modify your workflow, which was demonstrated in the [Iterate a loop with a Lambda function in Step Functions](tutorial-create-iterate-pattern-section.md) tutorial. You use the same Lambda function (`Iterator`) to iterate a loop for a specific number of times. In addition, you create another Lambda function to start a new execution of your workflow, and to decrement a count each time it starts a new execution. By setting the number of executions in the input, this state machine ends and restarts an execution a specified number of times.

The state machine you'll create implements the following states.


| State | Purpose | 
| --- | --- | 
| `ConfigureCount` |  A `Pass` state that configures the `count`, `index`, and `step` values that the `Iterator` Lambda function uses to step through iterations of work.  | 
|  `Iterator`  |  A `Task` state that references the `Iterator` Lambda function.  | 
| `IsCountReached` | A Choice state that uses a Boolean value from the Iterator function to decide whether the state machine should continue the example work, or move to the ShouldRestart state. | 
| `ExampleWork` | A Pass state that represents the Task state that would perform work in an actual implementation. | 
| `ShouldRestart` | A Choice state that uses the executionCount value to decide whether it should end one execution and start another, or simply end.  | 
| `Restart` | A Task state that uses a Lambda function to start a new execution of your state machine. Like the Iterator function, this function also decrements a count. The Restart state passes the decremented value of the count to the input of the new execution.  | 

## Prerequisites
<a name="tutorial-continue-new-prereq"></a>

Before you begin, go through the [Creating a Step Functions state machine that uses Lambda](tutorial-creating-lambda-state-machine.md) tutorial to ensure that you're familiar with using Lambda and Step Functions together.

## Step 1: Create a Lambda function to iterate a count
<a name="tutorial-continue-new-step-1"></a>

**Note**  
If you have completed the [Iterate a loop with a Lambda function in Step Functions](tutorial-create-iterate-pattern-section.md) tutorial, you can skip this step and use that Lambda function.

This section and the [Iterate a loop with a Lambda function in Step Functions](tutorial-create-iterate-pattern-section.md) tutorial show how you can use a Lambda function to track a count, for example, the number of iterations of a loop in your state machine. 

 The following Lambda function receives input values for `count`, `index`, and `step`. It returns these values with an updated `index` and a Boolean named `continue`. The Lambda function sets `continue` to `true` if the `index` is less than `count`.

Your state machine then implements a `Choice` state that executes some application logic if `continue` is `true`, or moves on to `ShouldRestart` if `continue` is `false`.

### Create the Iterate Lambda function
<a name="tutorial-continue-new-create-lambda-function"></a>

1. Open the [Lambda console](https://console.aws.amazon.com/lambda/home), and then choose **Create function**.

1. On the **Create function** page, choose **Author from scratch**.

1. In the **Basic information** section, configure your Lambda function, as follows:

   1. For **Function name**, enter `Iterator`.

   1. For **Runtime**, choose **Node.js 16.x**.

   1. Keep all the default selections on the page, and then choose **Create function**.

      When your Lambda function is created, make a note of its Amazon Resource Name (ARN) in the upper-right corner of the page, for example:

      ```
      arn:aws:lambda:region:123456789012:function:Iterator
      ```

1. Copy the following code for the Lambda function into the **Code source** section of the ***Iterator*** page in the Lambda console.

   ```
   exports.handler = function iterator (event, context, callback) {
     let index = event.iterator.index;
     let step = event.iterator.step;
     let count = event.iterator.count;
    
     index = index + step;
    
     callback(null, {
       index,
       step,
       count,
       continue: index < count
     })
   }
   ```

   This code accepts input values for `count`, `index`, and `step`. It increments the `index` by the value of `step` and returns these values, and the Boolean value of `continue`. The value of `continue` is `true` if `index` is less than `count`.

1. Choose **Deploy** to deploy the code.

### Test the Iterate Lambda function
<a name="tutorial-continue-new-step-1-test"></a>

To see your `Iterate` function working, run it with numeric values. You can provide input values for your Lambda function that mimic an iteration to see what output you get with specific input values. 

#### To test your Lambda function
<a name="tutorial-continue-new-test-lambda-function"></a>

1. In the **Configure test event** dialog box, choose **Create new test event**, and then type `TestIterator` for **Event name**.

1. Replace the example data with the following.

   ```
   {
     "Comment": "Test my Iterator function",
     "iterator": {
       "count": 10,
       "index": 5,
       "step": 1
     }
   }
   ```

   These values mimic what would come from your state machine during an iteration. The Lambda function increments the index and returns `continue` as `true`. When the index is not less than the `count`, it returns `continue` as `false`. For this test, the index has already incremented to `5`. The results should increment the `index` to `6` and set `continue` to `true`.

1. Choose **Create**.

1. On the ***Iterator*** page in your Lambda console, be sure **TestIterator** is listed, and then choose **Test**.

   The results of the test are displayed at the top of the page. Choose **Details** and review the result.

   ```
   {
     "index": 6,
     "step": 1,
     "count": 10,
     "continue": true
   }
   ```
**Note**  
If you set `index` to `9` for this test, the `index` increments to `10`, and `continue` is `false`. 

## Step 2: Create a Restart Lambda function to start a new Step Functions execution
<a name="tutorial-continue-new-step-3"></a>

1. Open the [Lambda console](https://console.aws.amazon.com/lambda/home), and then choose **Create function**.

1. On the **Create function** page, choose **Author from scratch**.

1. In the **Basic information** section, configure your Lambda function, as follows:

   1. For **Function name**, enter `Restart`.

   1. For **Runtime**, choose **Node.js 16.x**.

1. Keep all the default selections on the page, and then choose **Create function**.

   When your Lambda function is created, make a note of its Amazon Resource Name (ARN) in the upper-right corner of the page, for example:

   ```
   arn:aws:lambda:region:123456789012:function:Iterator
   ```

1. Copy the following code for the Lambda function into the **Code source** section of the ***Restart*** page in the Lambda console.

   The following code decrements a count of the number of executions, and starts a new execution of your state machine, including the decremented value.

   ```
   var aws = require('aws-sdk');
   var sfn = new aws.StepFunctions();
   
   exports.restart = function(event, context, callback) {
   
     let StateMachineArn = event.restart.StateMachineArn;
     event.restart.executionCount -= 1;
     event = JSON.stringify(event);
   
     let params = {
         input: event,
         stateMachineArn: StateMachineArn
     };
   
     sfn.startExecution(params, function(err, data) {
         if (err) callback(err);
         else callback(null,event);
     });
   
   }
   ```

1. Choose **Deploy** to deploy the code.

## Step 3: Create a state machine
<a name="tutorial-continue-new-step-4"></a>

Now that you've created your two Lambda functions, create a state machine. In this state machine, the `ShouldRestart` and `Restart` states are how you break your work across multiple executions.

**Example ShouldRestart Choice state**  
The following excerpt shows the `ShouldRestart``Choice` state. This state determines whether or not you should restart the execution.  

```
"ShouldRestart": {
"Type": "Choice",
"Choices": [
  {
    "Variable": "$.restart.executionCount",
    "NumericGreaterThan": 1,
    "Next": "Restart"
  }
],
```

The `$.restart.executionCount` value is included in the input of the initial execution. It's decremented by one each time the `Restart` function is called, and then placed into the input for each subsequent execution.

**Example Restart Task state**  
The following excerpt shows the `Restart``Task` state. This state uses the Lambda function you created earlier to restart the execution, and to decrement the count to track the remaining number of executions to start.  

```
"Restart": {
  "Type": "Task",
  "Resource": "arn:aws:lambda:region:123456789012:function:Restart",
  "Next": "Done"
},
```

**To create the state machine**

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home), choose **State machines** from the menu, then choose **Create state machine**.
**Important**  
Make sure that your state machine is under the same AWS account and Region as the Lambda functions you created earlier in [Step 1](#tutorial-continue-new-step-1) and [Step 2](#tutorial-continue-new-step-3).

1. Choose **Create from blank**.

1. Name your state machine, then choose **Continue** to edit your state machine in Workflow Studio.

1. For this tutorial, you'll write the [Amazon States Language](concepts-amazon-states-language.md) (ASL) definition of your state machine in the [Code editor](workflow-studio.md#wfs-interface-code-editor). To do this, choose **Code**.

1. Remove the existing boilerplate code and paste the following code. Remember to replace the ARNs in this code with the ARNs of the Lambda functions you created.

   ```
   {
       "Comment": "Continue-as-new State Machine Example",
       "StartAt": "ConfigureCount",
       "States": {
           "ConfigureCount": {
               "Type": "Pass",
               "Result": {
                   "count": 100,
                   "index": -1,
                   "step": 1
               },
               "ResultPath": "$.iterator",
               "Next": "Iterator"
           },
           "Iterator": {
               "Type": "Task",
               "Resource": "arn:aws:lambda:region:123456789012:function:Iterator",
               "ResultPath": "$.iterator",
               "Next": "IsCountReached"
           },
           "IsCountReached": {
               "Type": "Choice",
               "Choices": [
                   {
                       "Variable": "$.iterator.continue",
                       "BooleanEquals": true,
                       "Next": "ExampleWork"
                   }
               ],
               "Default": "ShouldRestart"
           },
           "ExampleWork": {
               "Comment": "Your application logic, to run a specific number of times",
               "Type": "Pass",
               "Result": {
                 "success": true
               },
               "ResultPath": "$.result",
               "Next": "Iterator"
           },
           "ShouldRestart": {
             "Type": "Choice",
             "Choices": [
               {
                 "Variable": "$.restart.executionCount",
                 "NumericGreaterThan": 0,
                 "Next": "Restart"
               }
             ],
             "Default": "Done"
           },
           "Restart": {
             "Type": "Task",
             "Resource": "arn:aws:lambda:region:123456789012:function:Restart",
             "Next": "Done"
           },
           "Done": {
               "Type": "Pass",
               "End": true 
           }
       }
   }
   ```

1. Specify a name for your state machine. To do this, choose the edit icon next to the default state machine name of **MyStateMachine**. Then, in **State machine configuration**, specify a name in the **State machine name** box.

   For this tutorial, enter the name **ContinueAsNew**.

1. (Optional) In **State machine configuration**, specify other workflow settings, such as state machine type and its execution role.

   For this tutorial, keep all the default selections in **State machine settings**.

   If you've [previously created an IAM role](procedure-create-iam-role.md) with the correct permissions for your state machine and want to use it, in **Permissions**, select **Choose an existing role**, and then select a role from the list. Or select **Enter a role ARN** and then provide an ARN for that IAM role.

1. In the **Confirm role creation** dialog box, choose **Confirm** to continue.

   You can also choose **View role settings** to go back to **State machine configuration**.
**Note**  
If you delete the IAM role that Step Functions creates, Step Functions can't recreate it later. Similarly, if you modify the role (for example, by removing Step Functions from the principals in the IAM policy), Step Functions can't restore its original settings later. 

1. Save the Amazon Resource Name (ARN) of this state machine in a text file. You'll need to provide the ARN while providing permission to the Lambda function to start a new Step Functions execution.

## Step 4: Update the IAM Policy
<a name="tutorial-continue-new-step-2"></a>

To make sure your Lambda function has permissions to start a new Step Functions execution, attach an inline policy to the IAM role you use for your `Restart` Lambda function. For more information, see [Embedding Inline Policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#embed-inline-policy-console) in the *IAM User Guide*.

**Note**  
You can update the `Resource` line in the previous example to reference the ARN of your `ContinueAsNew` state machine. This restricts the policy so that it can only start an execution of that specific state machine.

****  

```
{
 "Version":"2012-10-17",		 	 	 
 "Statement": [
     {
         "Sid": "VisualEditor0",
         "Effect": "Allow",
         "Action": [
             "states:StartExecution"
         ],
         "Resource": "arn:aws:states:us-east-2:123456789012:stateMachine:ContinueAsNew"
     }
 ]
}
```

## Step 5: Run the state machine
<a name="tutorial-continue-new-step-5"></a>

To start an execution, provide input that includes the ARN of the state machine and an `executionCount` for how many times it should start a new execution.

1.  On the **ContinueAsNew** page, choose **Start execution**.

   The **Start execution** dialog box is displayed.

1. In the **Start execution** dialog box, do the following:

   1. (Optional) Enter a custom execution name to override the generated default.
**Non-ASCII names and logging**  
Step Functions accepts names for state machines, executions, activities, and labels that contain non-ASCII characters. Because such characters will prevent Amazon CloudWatch from logging data, we recommend using only ASCII characters so you can track Step Functions metrics.

   1. In the **Input** box, enter the following JSON input to run your workflow.

      ```
      {
        "restart": {
          "StateMachineArn": "arn:aws:states:region:account-id:stateMachine:ContinueAsNew",
          "executionCount": 4
        }
      }
      ```

   1. Update the `StateMachineArn` field with the ARN for your `ContinueAsNew` state machine.

   1. Choose **Start execution**.

   1. The Step Functions console directs you to a page that's titled with your execution ID. This page is known as the *Execution Details* page. On this page, you can review the execution results as the execution progresses or after it's complete.

      To review the execution results, choose individual states on the **Graph view**, and then choose the individual tabs on the [Step details](concepts-view-execution-details.md#exec-details-intf-step-details) pane to view each state's details including input, output, and definition respectively. For details about the execution information you can view on the *Execution Details* page, see [Execution details overview](concepts-view-execution-details.md#exec-details-interface-overview).

      The **Graph view** displays the first of the four executions. Before it completes, it will pass through the `Restart` state and start a new execution.  
![\[Execution diagram showing the first execution out of four.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/execution-test1.png)

      As this execution completes, you can look at the next execution that's running. Select the **ContinueAsNew** link at the top to see the list of executions. You should see both the recently closed execution, and an ongoing execution that the `Restart` Lambda function started.

      When all the executions are complete, you should see four successful executions in the list. The first execution that was started displays the name you chose, and subsequent executions have a generated name.  
![\[Illustrative screenshot showing all executions have completed.\]](http://docs.aws.amazon.com/step-functions/latest/dg/images/execution-test1-complete.png)

# Accessing cross-account AWS resources in Step Functions
<a name="tutorial-access-cross-acct-resources"></a>

With the cross-account access support in Step Functions, you can share resources configured in different AWS accounts. In this tutorial, we walk you through the process of accessing a cross-account Lambda function defined in an account called **Production**. This function is invoked from a state machine in an account called **Development**. In this tutorial, the **Development** account is referred to as the *source account* and the **Production** account is the *target account* containing the target IAM role.

To start, in your `Task` state’s definition, you specify the target IAM role the state machine must assume before invoking the cross-account Lambda function. Then, modify the trust policy in the target IAM role to allow the source account to assume the target role temporarily. Also, to call the AWS resource, define the appropriate permissions in the target IAM role. Finally, update the source account’s execution role to specify the required permission to assume the target role.

You can configure your state machine to assume an IAM role for accessing resources from multiple AWS accounts. However, a state machine can assume only one IAM role at a given time based on the `Task` state’s definition.

**Note**  
Cross-Region AWS SDK integration and cross-Region AWS resource access aren't available in Step Functions.

## Prerequisites
<a name="tutorial-access-cross-acct-resources-prereq"></a>
+ This tutorial uses the example of a Lambda function for demonstrating how to set up cross-account access. You can use any other AWS resource, but make sure you’ve configured the resource in a different account.
**Important**  
IAM roles and resource-based policies delegate access across accounts only within a single partition. For example, assume that you have an account in US West (N. California) in the standard `aws` partition. You also have an account in China (Beijing) in the `aws-cn` partition. You can't use an Amazon S3 resource-based policy in your account in China (Beijing) to allow access for users in your standard `aws` account.
+ Make a note of the cross-account resource's Amazon Resource Name (ARN) in a text file. Later in this tutorial, you'll provide this ARN in your state machine's `Task` state definition. The following is an example of a Lambda function ARN:

  ```
  arn:aws:lambda:us-east-2:account-id:function:functionName
  ```
+ Make sure you've created the target IAM role that the state machine needs to assume.

## Step 1: Update the Task state definition to specify the target role
<a name="tutorial-access-cross-acct-resources-update-task-def"></a>

In the `Task` state of your workflow, add a `Credentials` field containing the identity the state machine must assume before invoking the cross-account Lambda function.

The following procedure demonstrates how to access a cross-account Lambda function called `Echo`. You can call any AWS resource by following these steps.

1. Open the [Step Functions console](https://console.aws.amazon.com/states/home?region=us-east-1#/) and choose **Create state machine**.

1. On the **Choose authoring method** page, choose **Design your workflow visually** and keep all the default selections.

1. To open Workflow Studio, choose **Next**.

1. On the **Actions** tab, drag and drop a `Task` state on the canvas. This invokes the cross-account Lambda function that's using this `Task` state.

1. On the **Configuration** tab, do the following:

   1. Rename the state to **Cross-account call**.

   1. For **Function name**, choose **Enter function name**, and then enter the Lambda function ARN in the box. For example, `arn:aws:lambda:us-east-2:111122223333:function:Echo`.

   1. For **Provide IAM role ARN**, specify the target IAM role ARN. For example, `arn:aws:iam::111122223333:role/LambdaRole`.
**Tip**  
Alternatively, you can also specify a [reference path](amazon-states-language-paths.md#amazon-states-language-reference-paths) to an existing key-value pair in the state’s JSON input that contains the IAM role ARN. To do this, choose **Get IAM role ARN at runtime from state input**. For an example of specifying a value by using a reference path, see [Specifying JSONPath as IAM role ARN](state-task.md#example-credentials-specify-dynamic-jsonpath).

1. Choose **Next**.

1. On the **Review generated code** page, choose **Next**.

1. On the **Specify state machine settings** page, specify details for the new state machine, such as a name, permissions, and logging level.

1. Choose **Create state machine**.

1. Make a note of the state machine's IAM role ARN and the state machine ARN in a text file. You'll need to provide these ARNs in the target account's trust policy.

Your `Task` state definition should now look similar to the following definition.

```
{
  "StartAt": "Cross-account call",
  "States": {
    "Cross-account call": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Credentials": {
        "RoleArn": "arn:aws:iam::111122223333:role/LambdaRole"
      },
      "Parameters": {
        "FunctionName": "arn:aws:lambda:us-east-2:111122223333:function:Echo",
      },
      "End": true
    }
  }
}
```

## Step 2: Update the target role's trust policy
<a name="tutorial-access-cross-acct-resources-update-target-trust-policy"></a>

The IAM role must exist in the target account and you must modify its trust policy to allow the source account to assume this role temporarily. Additionally, you can control who can assume the target IAM role.

After you create the trust relationship, a user from the source account can use the AWS Security Token Service (AWS STS) [AssumeRole](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) API operation. This operation provides temporary security credentials that enable access to AWS resources in a target account.

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. On the navigation pane of the console, choose **Roles** and then use the Search box to search for the target IAM role. For example, `LambdaRole`.

1. Choose the **Trust relationships** tab.

1. Choose **Edit trust policy** and paste the following trust policy. Make sure to replace the AWS account number and IAM role ARN. The `sts:ExternalId` field further controls who can assume the role. The state machine's name must include only characters that the AWS Security Token Service `AssumeRole` API supports. For more information, see [AssumeRole](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) in the *AWS Security Token Service API Reference*.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Action": "sts:AssumeRole",
         "Principal": {
           "AWS": "arn:aws:iam::account-id:role/ExecutionRole"  // The source account's state machine execution role ARN
         },
         "Condition": {  // Control which account and state machine can assume the target IAM role
           "StringEquals": {
             "sts:ExternalId": "arn:aws:states:region:account-id:stateMachine:testCrossAccount"   //// ARN of the state machine that will assume the role.
           }
         }
       }
     ]
   }
   ```

1. Keep this window open and proceed to the next step for further actions.

## Step 3: Add the required permission in the target role
<a name="tutorial-access-cross-acct-resources-add-permissions"></a>

Permissions in the IAM policies determine whether a specific request is allowed or denied. The target IAM role must have the correct permission to invoke the Lambda function.

1. Choose the **Permissions** tab.

1. Choose **Add permissions** and then choose **Create inline policy**.

1. Choose the **JSON** tab and replace the existing content with the following permission. Make sure to replace your Lambda function ARN.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Action": "lambda:InvokeFunction",
         "Resource": "arn:aws:lambda:us-east-2:111122223333:function:Echo"  // The cross-account AWS resource being accessed
       }
     ]
   }
   ```

1. Choose **Review policy**.

1. On the **Review policy** page, enter a name for the permission, and then choose **Create policy**.

## Step 4: Add permission in execution role to assume the target role
<a name="tutorial-access-cross-acct-resources-update-exec-role"></a>

Step Functions doesn’t automatically generate the [AssumeRole](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) policy for all cross-account service integrations. You must add the required permission in the state machine's execution role to allow it to assume a target IAM role in one or more AWS accounts.

1. Open your state machine's execution role in the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). To do this:

   1. Open the state machine that you created in [Step 1 in the source account](#tutorial-access-cross-acct-resources-update-task-def).

   1. On the **State machine detail** page, choose **IAM role ARN**.

1. On the **Permissions** tab, choose **Add permissions** and then choose **Create inline policy**.

1. Choose the **JSON** tab and replace the existing content with the following permission. Make sure to replace your Lambda function ARN.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Action": "sts:AssumeRole",
         "Resource": "arn:aws:iam::111122223333:role/LambdaRole"  // The target role to be assumed
       }
     ]
   }
   ```

1. Choose **Review policy**.

1. On the **Review policy** page, enter a name for the permission, and then choose **Create policy**.

## Workshops for learning Step Functions
<a name="workshops"></a>

**Workshop: [The Step Functions Workshop](https://catalog.workshops.aws/stepfunctions/en-US)**  
In this workshop, you will learn to use the primary features of Step Functions while building workflows. A series of interactive modules start by introducing you to basic workflows, task states, and error handling. You can continue to learn choice states for branch logic, map states for processing arrays, and parallel states for running multiple branches in parallel.

**Workshop: [Large-scale Data Processing with Step Functions](https://catalog.workshops.aws/serverless-data-processing)**  
Learn how serverless technologies such as Step Functions and Lambda can simplify management and scaling, offload undifferentiated tasks, and address the challenges of large-scale distributed data processing. Along the way, you will work with distributed map for high concurrency processing. The workshop also presents best practices for optimizing your workflows, and practical use cases for claims processing, vulnerability scanning, and Monte Carlo simulation.