|
| 1 | +#!/bin/bash |
| 2 | +# Tutorial: Using Lambda with Amazon SQS |
| 3 | +# Source: https://docs.aws.amazon.com/lambda/latest/dg/with-sqs-example.html |
| 4 | + |
| 5 | +WORK_DIR=$(mktemp -d) |
| 6 | +LOG_FILE="$WORK_DIR/lambda-sqs-$(date +%Y%m%d-%H%M%S).log" |
| 7 | +exec > >(tee -a "$LOG_FILE") 2>&1 |
| 8 | + |
| 9 | +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} |
| 10 | +if [ -z "$REGION" ]; then |
| 11 | + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" |
| 12 | + exit 1 |
| 13 | +fi |
| 14 | +export AWS_DEFAULT_REGION="$REGION" |
| 15 | +echo "Region: $REGION" |
| 16 | + |
| 17 | +RANDOM_ID=$(openssl rand -hex 4) |
| 18 | +ROLE_NAME="lambda-sqs-role-${RANDOM_ID}" |
| 19 | +FUNCTION_NAME="sqs-processor-${RANDOM_ID}" |
| 20 | +QUEUE_NAME="lambda-tut-queue-${RANDOM_ID}" |
| 21 | + |
| 22 | +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } |
| 23 | +trap 'handle_error $LINENO' ERR |
| 24 | + |
| 25 | +cleanup() { |
| 26 | + echo "" |
| 27 | + echo "Cleaning up resources..." |
| 28 | + [ -n "$EVENT_SOURCE_UUID" ] && \ |
| 29 | + aws lambda delete-event-source-mapping --uuid "$EVENT_SOURCE_UUID" 2>/dev/null && echo " Deleted event source mapping" |
| 30 | + aws lambda delete-function --function-name "$FUNCTION_NAME" 2>/dev/null && echo " Deleted function $FUNCTION_NAME" |
| 31 | + aws iam detach-role-policy --role-name "$ROLE_NAME" \ |
| 32 | + --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole 2>/dev/null |
| 33 | + aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null && echo " Deleted role $ROLE_NAME" |
| 34 | + [ -n "$QUEUE_URL" ] && aws sqs delete-queue --queue-url "$QUEUE_URL" 2>/dev/null && echo " Deleted queue $QUEUE_NAME" |
| 35 | + aws logs delete-log-group --log-group-name "/aws/lambda/$FUNCTION_NAME" 2>/dev/null && echo " Deleted log group" |
| 36 | + rm -rf "$WORK_DIR" |
| 37 | + echo "Cleanup complete." |
| 38 | +} |
| 39 | + |
| 40 | +# Step 1: Create IAM role |
| 41 | +echo "Step 1: Creating IAM role: $ROLE_NAME" |
| 42 | +ROLE_ARN=$(aws iam create-role --role-name "$ROLE_NAME" \ |
| 43 | + --assume-role-policy-document '{ |
| 44 | + "Version":"2012-10-17", |
| 45 | + "Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}] |
| 46 | + }' --query 'Role.Arn' --output text) |
| 47 | +aws iam attach-role-policy --role-name "$ROLE_NAME" \ |
| 48 | + --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole |
| 49 | +echo " Role ARN: $ROLE_ARN" |
| 50 | +echo " Waiting for role propagation..." |
| 51 | +sleep 10 |
| 52 | + |
| 53 | +# Step 2: Create Lambda function |
| 54 | +echo "Step 2: Creating Lambda function: $FUNCTION_NAME" |
| 55 | +cat > "$WORK_DIR/index.mjs" << 'EOF' |
| 56 | +export const handler = async (event) => { |
| 57 | + for (const message of event.Records) { |
| 58 | + console.log(`Processed message: ${message.body}`); |
| 59 | + } |
| 60 | + return { statusCode: 200 }; |
| 61 | +}; |
| 62 | +EOF |
| 63 | +(cd "$WORK_DIR" && zip function.zip index.mjs > /dev/null) |
| 64 | + |
| 65 | +aws lambda create-function --function-name "$FUNCTION_NAME" \ |
| 66 | + --zip-file "fileb://$WORK_DIR/function.zip" \ |
| 67 | + --handler index.handler --runtime nodejs22.x \ |
| 68 | + --role "$ROLE_ARN" --timeout 30 \ |
| 69 | + --architectures x86_64 \ |
| 70 | + --query 'FunctionArn' --output text |
| 71 | + |
| 72 | +echo " Waiting for function to become active..." |
| 73 | +aws lambda wait function-active-v2 --function-name "$FUNCTION_NAME" |
| 74 | + |
| 75 | +# Step 3: Test the function with a sample SQS event |
| 76 | +echo "Step 3: Testing Lambda with sample SQS event" |
| 77 | +cat > "$WORK_DIR/test-event.json" << EOF |
| 78 | +{ |
| 79 | + "Records": [{ |
| 80 | + "messageId": "test-msg-001", |
| 81 | + "body": "Hello from SQS test event", |
| 82 | + "attributes": {"ApproximateReceiveCount": "1", "SentTimestamp": "1545082649183"}, |
| 83 | + "messageAttributes": {}, |
| 84 | + "md5OfBody": "098f6bcd4621d373cade4e832627b4f6", |
| 85 | + "eventSource": "aws:sqs", |
| 86 | + "eventSourceARN": "arn:aws:sqs:$REGION:000000000000:test-queue", |
| 87 | + "awsRegion": "$REGION" |
| 88 | + }] |
| 89 | +} |
| 90 | +EOF |
| 91 | + |
| 92 | +aws lambda invoke --function-name "$FUNCTION_NAME" \ |
| 93 | + --payload "fileb://$WORK_DIR/test-event.json" \ |
| 94 | + --cli-binary-format raw-in-base64-out \ |
| 95 | + "$WORK_DIR/response.json" > /dev/null |
| 96 | +echo " Response: $(cat "$WORK_DIR/response.json")" |
| 97 | + |
| 98 | +# Step 4: Create SQS queue |
| 99 | +echo "Step 4: Creating SQS queue: $QUEUE_NAME" |
| 100 | +QUEUE_URL=$(aws sqs create-queue --queue-name "$QUEUE_NAME" --query 'QueueUrl' --output text) |
| 101 | +QUEUE_ARN=$(aws sqs get-queue-attributes --queue-url "$QUEUE_URL" \ |
| 102 | + --attribute-names QueueArn --query 'Attributes.QueueArn' --output text) |
| 103 | +echo " Queue ARN: $QUEUE_ARN" |
| 104 | + |
| 105 | +# Step 5: Create event source mapping |
| 106 | +echo "Step 5: Connecting SQS queue to Lambda" |
| 107 | +EVENT_SOURCE_UUID=$(aws lambda create-event-source-mapping \ |
| 108 | + --function-name "$FUNCTION_NAME" \ |
| 109 | + --batch-size 10 \ |
| 110 | + --event-source-arn "$QUEUE_ARN" \ |
| 111 | + --query 'UUID' --output text) |
| 112 | +echo " Event source mapping: $EVENT_SOURCE_UUID" |
| 113 | + |
| 114 | +# Step 6: Send test messages via SQS |
| 115 | +echo "Step 6: Sending test messages to SQS" |
| 116 | +aws sqs send-message --queue-url "$QUEUE_URL" --message-body "Hello from the Lambda-SQS tutorial" > /dev/null |
| 117 | +aws sqs send-message --queue-url "$QUEUE_URL" --message-body "This is message number 2" > /dev/null |
| 118 | +echo " Sent 2 messages. Waiting for Lambda to process them..." |
| 119 | +sleep 15 |
| 120 | + |
| 121 | +# Step 7: Verify in CloudWatch Logs |
| 122 | +echo "Step 7: Verifying Lambda processed the messages" |
| 123 | +LOG_GROUP="/aws/lambda/$FUNCTION_NAME" |
| 124 | +FOUND_LOGS=false |
| 125 | +for i in $(seq 1 15); do |
| 126 | + LOG_STREAM=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP" \ |
| 127 | + --order-by LastEventTime --descending --limit 1 \ |
| 128 | + --query 'logStreams[0].logStreamName' --output text 2>/dev/null || true) |
| 129 | + if [ -n "$LOG_STREAM" ] && [ "$LOG_STREAM" != "None" ]; then |
| 130 | + echo " Log stream: $LOG_STREAM" |
| 131 | + aws logs get-log-events --log-group-name "$LOG_GROUP" \ |
| 132 | + --log-stream-name "$LOG_STREAM" \ |
| 133 | + --query 'events[].message' --output text |
| 134 | + FOUND_LOGS=true |
| 135 | + break |
| 136 | + fi |
| 137 | + sleep 5 |
| 138 | +done |
| 139 | +if [ "$FOUND_LOGS" = false ]; then |
| 140 | + echo " Logs not available yet (this is normal — they can take a minute to appear)" |
| 141 | +fi |
| 142 | + |
| 143 | +echo "" |
| 144 | +echo "Tutorial complete." |
| 145 | +echo "Do you want to clean up all resources? (y/n): " |
| 146 | +read -r CHOICE |
| 147 | +if [[ "$CHOICE" =~ ^[Yy]$ ]]; then |
| 148 | + cleanup |
| 149 | +else |
| 150 | + echo "Resources left running. Manual cleanup commands:" |
| 151 | + echo " aws lambda delete-event-source-mapping --uuid $EVENT_SOURCE_UUID" |
| 152 | + echo " aws lambda delete-function --function-name $FUNCTION_NAME" |
| 153 | + echo " aws sqs delete-queue --queue-url $QUEUE_URL" |
| 154 | + echo " aws iam detach-role-policy --role-name $ROLE_NAME --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" |
| 155 | + echo " aws iam delete-role --role-name $ROLE_NAME" |
| 156 | +fi |
0 commit comments