AWS Step Functions orchestrates your business logic across Lambda functions, ECS tasks, and other AWS services — but failed executions don't make noise by default. A workflow that enters the FAILED state, a state machine that stops receiving triggers, or an execution stuck waiting for a callback: none of these create an external alert unless you've wired one up. CloudWatch Alarms help inside your AWS account, but Vigilmon gives you an external, independent signal that fires even when your AWS account itself has a problem.
This tutorial shows you how to wire Step Functions into Vigilmon for workflow availability monitoring, execution heartbeats, and smart alert thresholds.
What You'll Build
- A Lambda health handler that checks Step Functions state machine status
- A Vigilmon HTTP monitor for state machine availability
- A heartbeat ping at the end of your Step Functions workflows
- A failed-execution alerting strategy
Prerequisites
- An AWS account with at least one Step Functions state machine
- AWS CLI or CDK configured locally
- A free account at vigilmon.online
Step 1: Add a Health Lambda for Your State Machine
Deploy a Lambda function that checks your state machine's recent execution status and returns a health response Vigilmon can probe via API Gateway.
# handlers/health.py
import os
import json
import boto3
from datetime import datetime, timezone, timedelta
sfn = boto3.client("stepfunctions")
STATE_MACHINE_ARN = os.environ["STATE_MACHINE_ARN"]
def handler(event, context):
checks = {}
ok = True
# Check recent executions for failures
try:
# Get the last 5 executions
resp = sfn.list_executions(
stateMachineArn=STATE_MACHINE_ARN,
maxResults=5,
)
executions = resp.get("executions", [])
if not executions:
checks["executions"] = "no recent executions"
else:
latest = executions[0]
checks["latest_status"] = latest["status"]
checks["latest_start"] = latest["startDate"].isoformat()
# Flag if the latest execution failed
if latest["status"] in ("FAILED", "TIMED_OUT", "ABORTED"):
ok = False
checks["failure_reason"] = f"latest execution status: {latest['status']}"
# Flag if no successful execution in the last hour
one_hour_ago = datetime.now(timezone.utc) - timedelta(hours=1)
recent_successes = [
e for e in executions
if e["status"] == "SUCCEEDED" and e["startDate"] > one_hour_ago
]
checks["recent_successes"] = len(recent_successes)
except Exception as e:
checks["sfn_error"] = str(e)
ok = False
# Check state machine reachability
try:
sfn.describe_state_machine(stateMachineArn=STATE_MACHINE_ARN)
checks["state_machine_reachable"] = True
except Exception as e:
checks["state_machine_error"] = str(e)
ok = False
return {
"statusCode": 200 if ok else 503,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"status": "ok" if ok else "degraded", "checks": checks}),
}
Wire this as an API Gateway endpoint using SAM:
# template.yaml (excerpt)
HealthFunction:
Type: AWS::Serverless::Function
Properties:
Handler: handlers/health.handler
Runtime: python3.12
Environment:
Variables:
STATE_MACHINE_ARN: !Ref MyStateMachine
Policies:
- Statement:
- Effect: Allow
Action:
- states:ListExecutions
- states:DescribeStateMachine
Resource: !Ref MyStateMachine
Events:
HealthApi:
Type: HttpApi
Properties:
Path: /health
Method: GET
Deploy:
sam build && sam deploy
Step 2: Configure the Vigilmon HTTP Monitor
- Log in to Vigilmon → Add Monitor → HTTP.
- URL:
https://<api-id>.execute-api.<region>.amazonaws.com/health - Check interval: 60 seconds.
- Response timeout: 10 seconds.
- Expected status:
200. - JSON assertion: path
status, expected valueok.
Tip: The health Lambda above checks the last 5 executions. For workflows that run less than once per hour (e.g. nightly), adjust the lookback window in the Lambda to avoid false positives during quiet periods.
Step 3: Heartbeat at the End of Your Workflow
For workflows that run on a schedule (triggered by EventBridge), add a heartbeat task as the final state in your state machine. This confirms the entire workflow completed successfully, not just that the Lambda was invoked.
State machine definition (ASL)
{
"Comment": "Data processing workflow with Vigilmon heartbeat",
"StartAt": "ProcessData",
"States": {
"ProcessData": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "${ProcessDataFunction}",
"Payload.$": "$"
},
"Next": "TransformData"
},
"TransformData": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "${TransformFunction}",
"Payload.$": "$"
},
"Next": "PingVigilmon"
},
"PingVigilmon": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "${HeartbeatFunction}"
},
"End": true
}
}
}
Heartbeat Lambda
# handlers/heartbeat.py
import os
import urllib.request
def handler(event, context):
heartbeat_url = os.environ["VIGILMON_HEARTBEAT_URL"]
req = urllib.request.Request(heartbeat_url, method="POST")
with urllib.request.urlopen(req, timeout=5) as resp:
print(f"Vigilmon heartbeat sent: HTTP {resp.status}")
return {"status": "heartbeat_sent"}
Store the heartbeat URL in SSM Parameter Store:
aws ssm put-parameter \
--name "/myapp/prod/vigilmon-heartbeat-url" \
--value "https://vigilmon.online/api/heartbeat/<your-id>" \
--type SecureString
Reference it in the heartbeat Lambda's environment:
HeartbeatFunction:
Type: AWS::Serverless::Function
Properties:
Handler: handlers/heartbeat.handler
Runtime: python3.12
Environment:
Variables:
VIGILMON_HEARTBEAT_URL: "{{resolve:ssm:/myapp/prod/vigilmon-heartbeat-url}}"
In Vigilmon, create a Heartbeat monitor with a grace period matching your workflow schedule:
| EventBridge schedule | Recommended grace period | |---|---| | Every 15 minutes | 20 minutes | | Hourly | 75 minutes | | Daily at 2 AM | 26 hours |
Step 4: Alerting for Failed Executions
Step Functions integrates with CloudWatch for execution metrics, but Vigilmon adds an external layer for when CloudWatch itself is degraded or your state machine stops receiving events entirely.
Combine both approaches:
- CloudWatch Alarm on
ExecutionsFailedmetric → SNS → PagerDuty (catches failures within executions) - Vigilmon HTTP monitor → checks state machine health from outside AWS (catches AWS account issues)
- Vigilmon Heartbeat monitor → confirms scheduled workflows are completing (catches trigger failures)
| Alert type | Recommended channel | |---|---| | Execution failed | PagerDuty (immediate) | | Scheduled workflow missed | Slack data-engineering channel | | State machine unreachable | On-call email + Slack | | Status page | Public Vigilmon status page |
Step 5: Multi-Region Step Functions Monitoring
If you run state machines in multiple AWS regions for redundancy, monitor each independently.
Deploy the health Lambda and API Gateway to each region, then create one Vigilmon monitor per region:
| Region | Monitor name | URL |
|---|---|---|
| us-east-1 | Step Functions US | https://<api>.execute-api.us-east-1.amazonaws.com/health |
| eu-west-1 | Step Functions EU | https://<api>.execute-api.eu-west-1.amazonaws.com/health |
Group regional monitors under a single Status Page so stakeholders see one aggregate status.
What Vigilmon Catches That CloudWatch Misses
| Scenario | CloudWatch | Vigilmon | |---|---|---| | Execution fails | ExecutionsFailed metric fires | HTTP monitor catches via recent-execution check | | Scheduled workflow never triggers | No metric | Heartbeat grace period fires alert | | AWS account has IAM issue | Alarms may not fire | External check — unaffected | | State machine deleted or inactive | No alarm by default | HTTP monitor catches immediately | | Regional degradation | Needs per-region alarms | One monitor per region |
Step Functions makes complex workflows look simple — until one silently fails at 2 AM. External monitoring from Vigilmon gives your team the independent signal that catches failures before they cascade into business-visible outages.
Start monitoring your Step Functions workflows in under 5 minutes — register free at vigilmon.online.