AWSハンズオン - SQS + Lambdaでメッセージキュー処理を実装しよう【SAM版 / Windows対応】

AWS Basic
スポンサーリンク
スポンサーリンク

はじめに

「メッセージキューって何に使うの?」「エラーが起きたメッセージをどうやって管理するの?」という疑問を持っている方向けに、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 による完全クリーンアップ手順まで含む

Amazon検索[本 AWS 開発]

スポンサーリンク

SQS(メッセージキュー)とは

キューが解決する問題

SQSがない場合、送信者(API・バッチ)は処理者(Lambda)に直接データを渡します。処理者が落ちていたり過負荷だと、データが失われます。

SQSを挟むと、送信者はキューに投げるだけ。処理者は自分のペースでキューからメッセージを取り出せます。これが非同期処理の基本形です。

用語意味
キューメッセージを一時保管する「行列」。送信者と処理者を分離する
ポーリングLambdaが SQS を定期的に確認してメッセージを取り出す動作
可視性タイムアウトLambdaが処理中にメッセージを他から見えなくする時間
デッドレターキュー(DLQ)処理に繰り返し失敗したメッセージの退避先
maxReceiveCountDLQに移動するまでの最大受信(再試行)回数

スポンサーリンク

前提条件

以下のツールがインストール・設定済みであることを確認してください。

ツール確認コマンド最低バージョン目安
AWS CLI v2aws --version2.x
AWS SAM CLIsam --version1.x
Pythonpython --version3.12推奨
Gitgit --version-
VSCode-最新版推奨

AWS認証の確認

aws sts get-caller-identity

アカウントIDが表示されれば認証設定済みです。


使用するAWSサービス

サービス役割料金
SQS(スタンダードキュー)メッセージの一時保管・配信100万リクエスト/月まで無料
SQS(DLQ)処理失敗メッセージの退避同上
Lambdaメッセージ処理本体(Python)100万リクエスト無料枠あり
CloudWatch LogsLambda実行ログの保存5GBまで無料
S3SAMのデプロイパッケージ置き場自動作成・少量なのでほぼ無料

学習目的の短時間ハンズオンであれば、ほぼ無料枠内で収まります。


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.Arn

template.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テンプレートでは BatchDLQBatchQueueProcessFunction の順で記述しています。
これは 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.yaml

Step 6: sam deploy(デプロイ)

sam deploy

途中で変更内容が表示されて確認を求められます。

Deploy this changeset? [y/N]: y

y を入力して進めます。数分でデプロイが完了します。

デプロイ完了の確認

ターミナルに 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
----------------------------------------------------------------------

BatchQueueUrlBatchDLQUrl を控えておきます。(テスト時に使います)


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-1

BatchSize: 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

処理の流れ:

  1. Lambda が error を受信 → 例外発生(処理失敗)
  2. 可視性タイムアウト(180秒)後に再度キューに現れる
  3. 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-XXXX
aws 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-1
An 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 deployMissing --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のメリットを実感できたポイント

  • SQSPollerPolicy 1行で 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版との比較付き】


関連記事

Amazon検索[本 AWS 開発]

コメント