Skip to content
advanced Phase 4 · AWS Serverless

Step Functions

Orchestrate workflows with AWS Step Functions and state machines.

1h
0 problems
Topic Progress 0%

Step Functions Fundamentals

Step Functions Fundamentals

AWS Step Functions coordinate components of distributed applications through visual workflows.

Workflow Types

Type Max Duration Price Use Case
Standard 1 year Per state transition Long-running, audit trails
Express 5 minutes Per execution + duration High-volume, event processing

State Machine Definition (ASL)

{
  "Comment": "A simple workflow",
  "StartAt": "ProcessOrder",
  "States": {
    "ProcessOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ProcessOrder",
      "Next": "CheckInventory"
    },
    "CheckInventory": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:CheckInventory",
      "Next": "IsInStock"
    },
    "IsInStock": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.inStock",
          "BooleanEquals": true,
          "Next": "ShipOrder"
        }
      ],
      "Default": "NotifyCustomer"
    },
    "ShipOrder": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sqs:sendMessage",
      "Parameters": {
        "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/shipping-queue",
        "MessageBody.$": "$.order"
      },
      "End": true
    },
    "NotifyCustomer": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:NotifyCustomer",
      "End": true
    }
  }
}

State Types

Type Purpose
Task Execute work (Lambda, API Gateway, etc.)
Choice Branching logic (if/else)
Wait Pause execution (seconds, timestamp)
Parallel Execute multiple branches
Map Iterate over a collection
Pass Inject data or do nothing
Succeed End workflow successfully
Fail End workflow with error

Error Handling and Retries

Error Handling and Retries

Try/Catch Pattern

{
  "Type": "Task",
  "Resource": "arn:aws:lambda:us-east-1:xxx:function:my-function",
  "Retry": [
    {
      "ErrorEquals": ["States.TaskFailed"],
      "IntervalSeconds": 3,
      "MaxAttempts": 3,
      "BackoffRate": 2
    }
  ],
  "Catch": [
    {
      "ErrorEquals": ["States.ALL"],
      "ResultPath": "$.error",
      "Next": "HandleError"
    }
  ],
  "Next": "SuccessState"
}

Custom Error Codes

# Lambda function raising custom error
import json

def lambda_handler(event, context):
    if event['amount'] > 1000:
        raise Exception('ValidationError: Amount exceeds limit')
    
    return {'processed': True}
"Retry": [
  {
    "ErrorEquals": ["ValidationError"],
    "MaxAttempts": 0
  },
  {
    "ErrorEquals": ["States.TaskFailed"],
    "IntervalSeconds": 5,
    "MaxAttempts": 3,
    "BackoffRate": 2
  }
]

Catch States

"Catch": [
  {
    "ErrorEquals": ["ValidationError"],
    "Next": "ValidationFailed",
    "ResultPath": "$.error"
  },
  {
    "ErrorEquals": ["Lambda.ServiceException", "Lambda.SdkClientException"],
    "Next": "ServiceError",
    "ResultPath": "$.error"
  },
  {
    "ErrorEquals": ["States.ALL"],
    "Next": "GenericError",
    "ResultPath": "$.error"
  }
]

Parallel and Map States

Parallel and Map States

Parallel Execution

{
  "Type": "Parallel",
  "Branches": [
    {
      "StartAt": "ProcessPayment",
      "States": {
        "ProcessPayment": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:xxx:function:ProcessPayment",
          "End": true
        }
      }
    },
    {
      "StartAt": "ReserveInventory",
      "States": {
        "ReserveInventory": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:xxx:function:ReserveInventory",
          "End": true
        }
      }
    },
    {
      "StartAt": "SendConfirmation",
      "States": {
        "SendConfirmation": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:xxx:function:SendEmail",
          "End": true
        }
      }
    }
  ],
  "Next": "CombineResults"
}

Map State (Iterate)

{
  "Type": "Map",
  "ItemsPath": "$.orders",
  "MaxConcurrency": 10,
  "Iterator": {
    "StartAt": "ProcessItem",
    "States": {
      "ProcessItem": {
        "Type": "Task",
        "Resource": "arn:aws:lambda:xxx:function:ProcessItem",
        "End": true
      }
    }
  },
  "Next": "AggregateResults"
}

Map with Parameters

{
  "Type": "Map",
  "ItemsPath": "$.items",
  "Parameters": {
    "itemId.$": "$.itemId",
    "itemName.$": "$.itemName",
    "staticValue": "processed"
  },
  "MaxConcurrency": 5,
  "Iterator": {
    "StartAt": "Process",
    "States": {
      "Process": {
        "Type": "Task",
        "Resource": "arn:aws:lambda:xxx:function:Process",
        "End": true
      }
    }
  }
}

Step Functions Integration Patterns

Step Functions Integration Patterns

Direct AWS Service Integration

"PutItem": {
  "Type": "Task",
  "Resource": "arn:aws:states:::dynamodb:putItem",
  "Parameters": {
    "TableName": "MyTable",
    "Item": {
      "PK": {"S.$": "$.orderId"},
      "SK": {"S": "ORDER"},
      "Status": {"S": "PROCESSING"}
    }
  },
  "Next": "NextStep"
}

SQS Integration

"SendMessage": {
  "Type": "Task",
  "Resource": "arn:aws:states:::sqs:sendMessage",
  "Parameters": {
    "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue",
    "MessageBody.$": "$.payload",
    "MessageAttributes": {
      "Priority": {
        "DataType": "String",
        "StringValue": "high"
      }
    }
  }
}

Wait States

"WaitForCallback": {
  "Type": "Wait",
  "Seconds": 3600,
  "Next": "CheckStatus"
}

"WaitUntil": {
  "Type": "Wait",
  "Timestamp": "2024-01-15T12:00:00Z",
  "Next": "ProcessEvent"
}

Activity Workers

# External worker polling for tasks
import boto3
import json

sfn = boto3.client('stepfunctions')

# Get activity ARN
activity_arn = 'arn:aws:states:us-east-1:xxx:activity:my-activity'

# Poll for task
response = sfn.get_activity_task(
    activityArn=activity_arn,
    workerName='worker-1'
)

if 'taskToken' in response:
    # Process task
    result = {'status': 'completed', 'data': 'processed'}
    
    # Send success
    sfn.send_task_success(
        taskToken=response['taskToken'],
        output=json.dumps(result)
    )

Step Functions Best Practices

Step Functions Best Practices

Architecture Patterns

┌─────────────────────────────────────────────────────────────┐
│                Order Processing Workflow                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Start ──▶ Validate ──▶ Check ──┬──▶ Ship (Parallel)       │
│                 │               │     ├─ Payment            │
│                 │               │     ├─ Inventory          │
│                 ▼               │     └─ Notification       │
│            [Invalid]            │                          │
│                                  ▼                          
│                              [Complete]                     │
└─────────────────────────────────────────────────────────────┘

Best Practices

  1. Use Express workflows for high-volume, short-duration tasks
  2. Use Standard workflows for auditable, long-running processes
  3. Implement retry policies instead of manual error handling
  4. Use Map state instead of parallel for dynamic iteration
  5. Pass data efficiently using ResultPath and OutputPath
  6. Keep states simple - one action per state
  7. Use activity workers for non-AWS integrations

Cost Optimization

Type Pricing
Standard $0.025 per 1,000 state transitions
Express $1.00 per 1M executions + $0.000025 per 1,000 GB-seconds
# Create state machine
aws stepfunctions create-state-machine \
  --name my-workflow \
  --definition file://workflow.json \
  --role-arn arn:aws:iam::xxx:role/StepFunctionsRole

# Start execution
aws stepfunctions start-execution \
  --state-machine-arn arn:aws:states:us-east-1:xxx:stateMachine:my-workflow \
  --input '{"orderId": "123", "amount": 99.99}'

# Check execution history
aws stepfunctions describe-execution \
  --execution-arn arn:aws:states:us-east-1:xxx:execution:my-workflow:xxx