[チュートリアル] Amazon SQSメッセージを処理するLambda関数を作成してみた

2022.01.28

こんにちは、CX事業本部 IoT事業部の若槻です。

Amazon SQSは、AWS上で疎結合でスケーラブルなシステムを実装するのに役立つフルマネージド型のメッセージキューイングサービスです。

しかし私は今までAmazon SQSを使う機会がなかなか無く、いい加減触ってみようかなと思っていたところ、ちょうど良さそうなチュートリアルを見つけたので、今回やってみました。

やってみた

やってみたのは、次のAmazon SQSメッセージを処理するLambda関数を作成するチュートリアルです。

実行ロールを作成する

Lambda関数実行用のIAMロールを作成します。

https://console.aws.amazon.com/iam/home#/roles を開き、[ロールの作成]をクリック。

[信頼されたエンティティ]でAWS サービス、[ユースケースの選択]でLambdaを選択し、[次のステップ]をクリック。

AWSLambdaSQSQueueExecutionRoleを選択し、[次のステップ]をクリック。

ちなみにAWSLambdaSQSQueueExecutionRoleのポリシーの概要は次のようになります。Lambda関数がSQSメッセージを読み取り、CloudWatch Logsにログを書き込むためのアクセス許可です。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "sqs:ReceiveMessage",
        "sqs:DeleteMessage",
        "sqs:GetQueueAttributes",
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}

[タグの追加]では何もせずに[次のステップ]をクリック。

[確認]では、[ロール名]でlambda-sqs-roleを指定して、[ロールの作成]をクリック。

作成できました。

関数を作成する

Node.jsランタイムで実行可能なLambda関数のハンドラーコードindex.jsを次の通り作成します。

index.js

exports.handler = async function(event, context) {
  event.Records.forEach(record => {
    const { body } = record;
    console.log(body);
  });
  return {};
}

デプロイパッケージを作成します。

$ zip function.zip index.js

AWS CLIのlambda create-functionコマンドを実行してLambda関数を作成します。

$ ACCOUNT_ID=<アカウントID>
$ aws lambda create-function \
  --function-name ProcessSQSRecord \
  --zip-file fileb://function.zip \
  --handler index.handler \
  --runtime nodejs12.x \
  --role arn:aws:iam::${ACCOUNT_ID}:role/lambda-sqs-role

マネジメントコンソールを見るとLambda関数がちゃんと作成されています。

関数をテストする

次のSQSメッセージのレコードを記載したinput.txtファイルを作成します。

input.txt

{
  "Records": [
    {
      "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
      "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
      "body": "test",
      "attributes": {
          "ApproximateReceiveCount": "1",
          "SentTimestamp": "1545082649183",
          "SenderId": "AIDAIENQZJOLO23YVJ4VO",
          "ApproximateFirstReceiveTimestamp": "1545082649185"
      },
      "messageAttributes": {},
      "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
      "eventSource": "aws:sqs",
      "eventSourceARN": "arn:aws:sqs:ap-northeast-1:123456789012:my-queue",
      "awsRegion": "ap-northeast-1"
    }
  ]
}

lambda invokeコマンドを次の通り実行します。するとInvalid base64というエラーとなりました。

$ aws lambda invoke \
  --function-name ProcessSQSRecord \
  --payload file://input.txt outputfile.txt

Invalid base64: "{
  "Records": [
    {
      "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
      "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
      "body": "test",
      "attributes": {
          "ApproximateReceiveCount": "1",
          "SentTimestamp": "1545082649183",
          "SenderId": "AIDAIENQZJOLO23YVJ4VO",
          "ApproximateFirstReceiveTimestamp": "1545082649185"
      },
      "messageAttributes": {},
      "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
      "eventSource": "aws:sqs",
      "eventSourceARN": "arn:aws:sqs:ap-northeast-1:123456789012:my-queue",
      "awsRegion": "ap-northeast-1"
    }
  ]
}
"

なるほどAWS CLI v2を使っている場合はペイロードをBase64エンコードする必要があるんですね。

簡単にまとめれば、バイナリパラメーター(blob)を指定する際にはBase64でエンコードしてね、ということです。lambda invokeの--payloadはblobで指定することになっています。そのためAWS CLI v2ではペイロードをBase64でエンコードする必要があるわけです。それでは実例も交えて確認してみましょう。

作業環境のAWS CLIバージョンを確認するとV2です。なのでBase64エンコードが必要です。

$  aws --version
aws-cli/2.0.28 Python/3.7.4 Darwin/20.6.0 botocore/2.0.0dev32

今回はとりあえずの回避策としてマネジメントコンソールからテストをしてみます。

実行できました。関数がSQSのメッセージのレコードを処理できています。

Amazon SQS キュー を作成する

Amazon SQS コンソールを開き、[キューを作成]をクリック。

ここでキューの設定が色々出来るのですが、標準キューで[名前]をMyQueueと指定し、

[キューを作成]をクリック。

キューを作成できました。このキューのARNを控えます。

イベントソースを設定する

先程のARNを指定して、create-event-source-mappingコマンドを次の通り実行します。これによりAmazon SQS キューと Lambda 関数の間イベントソースマッピングを設定します。

$ QUEUE_ARN=<キューのARN>
$ aws lambda create-event-source-mapping \
  --function-name ProcessSQSRecord \
  --batch-size 10 \
  --event-source-arn ${QUEUE_ARN}

動作確認

先程作成したキューの詳細ページで[メッセージを送受信]をクリック。

[メッセージ本文]を指定して、[メッセージを送信]をクリックしキューメッセージを送信します。

Lambda関数のCloudWatch Logsのログイベントを見ると、キューメッセージを受信していることを確認できました!

おわりに

Amazon SQSメッセージを処理するLambda関数を作成するチュートリアルをやってみました。

Amazon SQSに関して今までは認定試験の勉強で仕様や実装パターンを覚えるだけの机上の知識しかありませんでしたが、今回触ってみて何となくの雰囲気がつかめました。

以上