はじめに
「メッセージキューって何に使うの?」「エラーが起きたメッセージをどうやって管理するの?」という疑問を持っている方向けに、Amazon SQS + Lambda によるメッセージキュー処理をゼロから構築するハンズオンを紹介します。
今回のハンズオンでは、AWS SAM(Serverless Application Model) を使って以下の構成を実装します。
送信者(AWS CLI)
↓ メッセージ送信
SQS キュー(BatchQueue)
↓ Lambda がポーリング(自動)
Lambda(Python 3.12 / ProcessFunction)
↓ 処理成功 → メッセージ削除(自動)
↓ 処理失敗(3回)→ DLQに移動
SQS デッドレターキュー(BatchDLQ)
↓ ログ出力
CloudWatch Logsこのハンズオンで体験できること:
- メッセージの送信・受信の仕組み(キューとLambdaのポーリング構造)
- バッチ処理(最大5件まとめてLambdaに渡す)
- デッドレターキュー(DLQ)(失敗メッセージを退避・後処理できる仕組み)
- SAMテンプレート1ファイルでSQS・DLQ・Lambda・IAM権限を一括管理
この記事の特徴:
- Windows(VSCode + コマンドプロンプト)での実際の手順を詳細に解説
- DLQが動くまでの待機時間など、つまずきやすいポイントに注意書きあり
- ハンズオン完了後の
sam deleteによる完全クリーンアップ手順まで含む
SQS(メッセージキュー)とは
キューが解決する問題
SQSがない場合、送信者(API・バッチ)は処理者(Lambda)に直接データを渡します。処理者が落ちていたり過負荷だと、データが失われます。
SQSを挟むと、送信者はキューに投げるだけ。処理者は自分のペースでキューからメッセージを取り出せます。これが非同期処理の基本形です。
| 用語 | 意味 |
|---|---|
| キュー | メッセージを一時保管する「行列」。送信者と処理者を分離する |
| ポーリング | Lambdaが SQS を定期的に確認してメッセージを取り出す動作 |
| 可視性タイムアウト | Lambdaが処理中にメッセージを他から見えなくする時間 |
| デッドレターキュー(DLQ) | 処理に繰り返し失敗したメッセージの退避先 |
| maxReceiveCount | DLQに移動するまでの最大受信(再試行)回数 |
前提条件
以下のツールがインストール・設定済みであることを確認してください。
| ツール | 確認コマンド | 最低バージョン目安 |
|---|---|---|
| AWS CLI v2 | aws --version | 2.x |
| AWS SAM CLI | sam --version | 1.x |
| Python | python --version | 3.12推奨 |
| Git | git --version | - |
| VSCode | - | 最新版推奨 |
AWS認証の確認
aws sts get-caller-identityアカウントIDが表示されれば認証設定済みです。
使用するAWSサービス
| サービス | 役割 | 料金 |
|---|---|---|
| SQS(スタンダードキュー) | メッセージの一時保管・配信 | 100万リクエスト/月まで無料 |
| SQS(DLQ) | 処理失敗メッセージの退避 | 同上 |
| Lambda | メッセージ処理本体(Python) | 100万リクエスト無料枠あり |
| CloudWatch Logs | Lambda実行ログの保存 | 5GBまで無料 |
| S3 | SAMのデプロイパッケージ置き場 | 自動作成・少量なのでほぼ無料 |
学習目的の短時間ハンズオンであれば、ほぼ無料枠内で収まります。
Step 1: プロジェクトフォルダを開く
VSCodeでプロジェクトフォルダを開きます。
cd C:\my-aws\aws-learning-projects\sqs-lambda-queueフォルダ構造
sqs-lambda-queue/
├── template.yaml # SAMテンプレート(SQS + DLQ + Lambda定義)
├── samconfig.toml # デプロイ設定(gitignore対象・毎回手動作成が必要)
├── docs/
│ ├── 1_console.md # AWSコンソール版手順
│ └── 2_sam.md # SAM版手順
└── src/
└── app.py # Lambda関数(メッセージ処理・DLQテスト用エラー機能)Step 2: SAMテンプレートの確認(template.yaml)
template.yaml がAWSリソース全体の設計図です。SQS・DLQ・Lambda・IAM権限をすべてこのファイル1つで定義します。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SQS + Lambda message queue processing
Globals:
Function:
Runtime: python3.12
Timeout: 30
MemorySize: 128
Resources:
BatchDLQ:
Type: AWS::SQS::Queue
Properties:
MessageRetentionPeriod: 86400 # メッセージ保持期間: 1日(86400秒)
# メインキュー
BatchQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 180 # Lambda タイムアウト(30s) × 6 = 180s
RedrivePolicy:
deadLetterTargetArn: !GetAtt BatchDLQ.Arn # DLQのARNを自動参照
maxReceiveCount: 3 # 3回失敗でDLQに移動
# Lambda 関数
ProcessFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: app.lambda_handler
Description: SQSからメッセージを受信して処理するLambda関数
Policies:
- SQSPollerPolicy: # SQS から読み取る権限を自動付与
QueueName: !GetAtt BatchQueue.QueueName
Events:
SQSEvent:
Type: SQS
Properties:
Queue: !GetAtt BatchQueue.Arn # メインキューと自動連携
BatchSize: 5 # 一度に最大5件まとめて処理
Outputs:
BatchQueueUrl:
Description: "メインキューのURL"
Value: !Ref BatchQueue
BatchDLQUrl:
Description: "DLQのURL"
Value: !Ref BatchDLQ
ProcessFunctionArn:
Description: "Lambda 関数 ARN"
Value: !GetAtt ProcessFunction.Arntemplate.yaml のポイント解説
SQSPollerPolicy(SAM組み込みポリシー)sqs:ReceiveMessage / sqs:DeleteMessage / sqs:GetQueueAttributes の3つの権限が1行で自動付与されます。コンソール版では AWSLambdaSQSQueueExecutionRole を IAM コンソールで手動アタッチする必要があります。
RedrivePolicy: !GetAtt BatchDLQ.Arn
DLQのARNをSAMが自動参照します。コンソール版ではDLQを先に作成してARNをコピー・貼り付けする必要がありますが、SAMではその手間が不要です。
VisibilityTimeout: 180
Lambda タイムアウト(30秒)× 6 = 180秒。これはAWSの推奨値です。処理中にタイムアウトが切れると、同じメッセージが再度キューに現れて二重処理が発生するため、Lambda タイムアウト × 6 以上を設定するのがベストプラクティスです。
Type: SQS イベント
SQS と Lambda のイベントソースマッピング(「トリガー」)を自動作成します。コンソール版では Lambda の「トリガーを追加」画面で手動設定が必要です。
DLQ登場の順序について:
SAMテンプレートではBatchDLQ→BatchQueue→ProcessFunctionの順で記述しています。
これは CloudFormation の依存解決の都合上、参照先(DLQ)を先に定義する必要があるためです。
コンソール版も同じ理由で「DLQ → メインキュー → Lambda」の順で作成します。
Step 3: Lambdaコードの確認(src/app.py)
src/app.py がメッセージ処理の本体です。SQSからのメッセージをループ処理し、本文が error の場合は意図的に例外を発生させてDLQへの振り分けをテストできます。
import json
import datetime
def lambda_handler(event, context):
results = []
for record in event["Records"]: # SQSからの各メッセージを順番に処理
message_id = record["messageId"]
body = record["body"]
# DLQテスト用: "error" というメッセージを受信したら意図的に例外を発生させる
if body.strip().lower() == "error":
raise ValueError(f"意図的なエラー: messageId={message_id}, body={body}")
now = datetime.datetime.now(datetime.timezone.utc)
result = {
"messageId": message_id,
"body": body,
"processedAt": now.isoformat(),
"status": "processed",
}
print(json.dumps(result, ensure_ascii=False))
results.append(result)
print(json.dumps({"processedCount": len(results)}, ensure_ascii=False))
return {"processedCount": len(results), "results": results}app.py のポイント解説
event["Records"]
SQSからのメッセージはリスト形式で渡されます。BatchSize: 5 の場合、最大5件がまとめて渡されるため、for ループで1件ずつ処理します。
raise ValueError(...)
例外を発生させると Lambda が失敗扱いになり、SQSがメッセージを再試行します。3回失敗するとDLQへ移動します。これがDLQの動作確認に使えます。
外部ライブラリ不使用
標準ライブラリ(json, datetime)のみ使用するため、requirements.txt が不要です。
Step 4: samconfig.toml を作成する
samconfig.toml は .gitignore で管理外のため、毎回手動で作成する必要があります。
sqs-lambda-queue/samconfig.toml を新規作成して以下を貼り付けてください。
version = 0.1
[default.deploy.parameters]
stack_name = "sqs-lambda-queue-stack"
resolve_s3 = true
s3_prefix = "sqs-lambda-queue-stack"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
disable_rollback = true
image_repositories = []
[default.global.parameters]
region = "ap-northeast-1"【注意】
samconfig.tomlの置き場所
sqs-lambda-queue/フォルダの直下に置く必要があります。
別のフォルダに置くと以下のエラーが発生します:Error: Missing option '--stack-name', 'sam deploy --guided' can be used to...
Step 5: sam build(ビルド)
cd C:\my-aws\aws-learning-projects\sqs-lambda-queue
sam build成功すると以下のように表示されます:
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yamlStep 6: sam deploy(デプロイ)
sam deploy途中で変更内容が表示されて確認を求められます。
Deploy this changeset? [y/N]: yy を入力して進めます。数分でデプロイが完了します。
デプロイ完了の確認
ターミナルに Outputs が表示されます。
CloudFormation outputs from deployed stack
----------------------------------------------------------------------
Outputs
----------------------------------------------------------------------
Key BatchQueueUrl
Value https://sqs.ap-northeast-1.amazonaws.com/123456789012/sqs-lambda-queue-stack-BatchQueue-XXXX
Key BatchDLQUrl
Value https://sqs.ap-northeast-1.amazonaws.com/123456789012/sqs-lambda-queue-stack-BatchDLQ-XXXX
Key ProcessFunctionArn
Value arn:aws:lambda:ap-northeast-1:123456789012:function:sqs-lambda-queue-stack-ProcessFunction-XXXX
----------------------------------------------------------------------BatchQueueUrl と BatchDLQUrl を控えておきます。(テスト時に使います)
Step 7: 動作テスト
7-1. 正常処理テスト
まず環境変数にキューのURLを設定します。
set QUEUE_URL=https://sqs.ap-northeast-1.amazonaws.com/123456789012/sqs-lambda-queue-stack-BatchQueue-XXXXメッセージを送信します。
aws sqs send-message ^
--queue-url %QUEUE_URL% ^
--message-body "こんにちは、SQS!" ^
--region ap-northeast-1レスポンス例:
{
"MD5OfMessageBody": "...",
"MessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}CloudWatch Logs でログを確認(数秒後):
aws logs tail /aws/lambda/sqs-lambda-queue-stack-ProcessFunction-XXXX --follow期待するログ出力:
{"messageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "body": "こんにちは、SQS!", "processedAt": "2026-02-22T10:00:00.000000+00:00", "status": "processed"}
{"processedCount": 1}"status": "processed" が表示されれば正常処理完了です。
7-2. 複数メッセージテスト(バッチ処理確認)
aws sqs send-message --queue-url %QUEUE_URL% --message-body "メッセージ1" --region ap-northeast-1
aws sqs send-message --queue-url %QUEUE_URL% --message-body "メッセージ2" --region ap-northeast-1
aws sqs send-message --queue-url %QUEUE_URL% --message-body "メッセージ3" --region ap-northeast-1BatchSize: 5 なので、3件まとめて Lambda に渡される可能性があります(タイミングによる)。まとめて渡された場合のログ:
{"messageId": "...", "body": "メッセージ1", "processedAt": "...", "status": "processed"}
{"messageId": "...", "body": "メッセージ2", "processedAt": "...", "status": "processed"}
{"messageId": "...", "body": "メッセージ3", "processedAt": "...", "status": "processed"}
{"processedCount": 3}"processedCount": 3 が1回のLambda呼び出しで表示されれば、バッチ処理(まとめて処理)が機能しています。
7-3. DLQテスト(処理失敗 → DLQへの振り分け確認)
aws sqs send-message ^
--queue-url %QUEUE_URL% ^
--message-body "error" ^
--region ap-northeast-1処理の流れ:
- Lambda が
errorを受信 → 例外発生(処理失敗) - 可視性タイムアウト(180秒)後に再度キューに現れる
- 3回失敗 → DLQ に移動
注意:DLQ に移動するまで最大 180秒 × 3回 ≒ 9分かかります。
すぐに確認したい場合は、CloudFormation コンソールでキューの可視性タイムアウトを一時的に短く(例: 10秒)して試すとよいです。
DLQ にメッセージが届いたか確認(CLI):
set DLQ_URL=https://sqs.ap-northeast-1.amazonaws.com/123456789012/sqs-lambda-queue-stack-BatchDLQ-XXXXaws sqs receive-message ^
--queue-url %DLQ_URL% ^
--region ap-northeast-1レスポンス例(メッセージが届いていれば表示されます):
{
"Messages": [
{
"MessageId": "...",
"Body": "error",
"ReceiptHandle": "...",
"MD5OfBody": "..."
}
]
}"Body": "error" のメッセージが表示されれば DLQ 動作確認完了です。
receive-messageが空を返す場合:
DLQ にまだ届いていないか、すでに一度受信済みの状態です(SQSは受信後に可視性タイムアウトが入る)。
SQS コンソール →BatchDLQ→ 「メッセージをポーリング」でも確認できます。
Step 8: AWSコンソールで確認(任意)
デプロイしたリソースをコンソールから目視確認できます。
- SQS(メインキュー): SQS →
sqs-lambda-queue-stack-BatchQueue-XXXX→ 「メッセージを送受信」で残件数確認 - SQS(DLQ): SQS →
sqs-lambda-queue-stack-BatchDLQ-XXXX→ 「メッセージをポーリング」でDLQの中身確認 - Lambda: Lambda → 関数 →
sqs-lambda-queue-stack-ProcessFunction-XXXX→ 「設定」→「トリガー」でSQSトリガーを確認 - CloudWatch Logs: Lambda → 対象関数 → 「モニタリング」タブ → 「CloudWatch Logs を表示」
Step 9: リソースの削除
課金を止めるために、ハンズオン完了後は必ずリソースを削除してください。
sam delete --stack-name sqs-lambda-queue-stack --region ap-northeast-1対話式で確認が入ります。両方 y で進めます。
Are you sure you want to delete the stack sqs-lambda-queue-stack? [y/N]: y
Are you sure you want to delete the folder sqs-lambda-queue-stack in S3? [y/N]: y削除完了の確認
aws cloudformation describe-stacks --stack-name sqs-lambda-queue-stack --region ap-northeast-1An error occurred (ValidationError): Stack with id sqs-lambda-queue-stack does not existこのメッセージが表示されれば削除完了です。
メッセージが残っていた場合:
sam deleteで SQS キュー内に残っているメッセージも一緒に削除されます。
DLQ に残ったメッセージの内容を記録しておきたい場合は、削除前にaws sqs receive-messageで確認しておいてください。
トラブルシューティング
| 症状 | 原因 | 対処 |
|---|---|---|
sam build が失敗する | src/app.py が存在しない | src/ フォルダと app.py が正しい場所にあるか確認 |
sam deploy が Missing --stack-name エラー | samconfig.toml がない | sqs-lambda-queue/ 直下に正しく作成されているか確認 |
| メッセージ送信後もログが出ない | Lambda がポーリングするまでのタイムラグ | 数秒〜十数秒待ってから CloudWatch Logs を確認 |
| DLQ にメッセージが届かない | 可視性タイムアウト(180秒)× 3回 の待機中 | 最大9分待つ |
receive-message が空のレスポンスを返す | DLQ にまだ届いていない、またはすでに受信済み | 時間をおいて再試行 |
| Lambda が 500 エラー | コードの構文エラーなど | CloudWatch Logs でエラー内容を確認 |
まとめ
今回のハンズオンで実現したこと:
| 確認項目 | 内容 |
|---|---|
| 正常処理 | SQSにメッセージを送信 → Lambdaが自動受信・処理・削除 |
| バッチ処理 | 複数メッセージをまとめてLambdaに渡す(BatchSize: 5) |
| DLQ動作 | 失敗メッセージが3回再試行後にDLQへ自動移動 |
| 削除 | sam delete 1コマンドで全リソースをクリーンアップ |
SAMのメリットを実感できたポイント
SQSPollerPolicy1行で IAM 権限の設定が完了(コンソール版では手動でポリシーをアタッチ)!GetAtt BatchDLQ.ArnでARNの手動コピー不要(コンソール版ではDLQ作成後にARNをコピー・貼り付け)sam deleteでSQS×2・Lambda・IAMロール・S3を一括削除
このハンズオンの発展形
- SNS との組み合わせ — SQS の前段に SNS を置くと、複数の SQS キューに同時配信(ファンアウト)できる
- メッセージフィルタリング — SQSのメッセージ属性を使って特定のメッセージだけをLambdaに渡す
- 可視性タイムアウトの動的変更 — 処理に時間がかかる場合はLambdaから
ChangeMessageVisibilityを呼ぶ - DLQ のアラーム設定 — CloudWatch アラームでDLQにメッセージが届いたらSlack通知
コンソール操作と比較してみる
SAMが裏で何をやっているか、全く同じ構成をAWSコンソールのみで手作業で構築する手順をまとめました。コンソール版では「DLQ作成 → メインキュー作成 → Lambda作成 → IAM権限追加 → トリガー追加」の順で6つのリソース設定が必要です。
- AWSコンソールだけでSQS + Lambdaキュー処理を構築する手順【SAM版との比較付き】
コメント