ElasticMQを使ってローカルでAWS SQSをモックする
なぜモックするのか
ローカルでLambdaを実行する際に、AWSのSQSと連携せずに動作確認を行いたい。
ElasticMQはSQS互換のメッセージキューシステム。こちらをローカルで動作させていきます。
ElasticMQのセットアップ
ElasticMQのDockerイメージが公開されているので、今回はDocker Composeを使ってセットアップしていきます。
docker-compose.yml 作成
version: "3"
services:
elasticmq:
container_name: elasticmq
image: softwaremill/elasticmq:latest
ports:
- "9324:9324"
- "9325:9325"
networks:
- sam-local
networks:
sam-local:
external: true
今回、sam localを利用して動作確認をしていきます。
sam localのコンテナからElasticMQのコンテナへ通信できるように、docker networkを作成しましょう。
docker network create sam-local
ElasticMQ起動
docker-composeでElasticMQを起動する。
docker-compose up -d
以下のURLで管理画面を開くことができる。
http://localhost:9325/
今は何のキューも作成していないので、寂しいですね。
ではキューを作成していきましょう。
動作確認
キューを作成
--endpoint-url
を指定することで、AWSではなくローカルのElasticMQへ接続できます。
aws sqs create-queue --queue-name test-queue --endpoint-url http://localhost:9324
作成されたキューを確認(管理画面でもOK)
aws sqs list-queues --endpoint-url http://localhost:9324
{
"QueueUrls": [
"http://localhost:9324/000000000000/test-queue"
]
}
AWS CLIで動作確認
メッセージの送受信
以下のコマンドでメッセージを送信してみましょう。
aws sqs send-message --queue-url http://localhost:9324/queue/test-queue --message-body "ElasticMQ Test Message" --endpoint-url http://localhost:9324
管理画面を見るとメッセージが送信されたことが確認できます。
では次に、以下のコマンドで送信されたメッセージを受信してみましょう。
aws sqs receive-message --queue-url http://localhost:9324/queue/test-queue --endpoint-url http://localhost:9324
{
"Messages": [
{
"MessageId": "65ba8f9b-3c22-4220-9e92-b0f5b469ef85",
"ReceiptHandle": "65ba8f9b-3c22-4220-9e92-b0f5b469ef85#06e57300-cb75-45fb-ae7c-27b349179980",
"MD5OfBody": "b336d90ba4892d57a9cc3140502d4634",
"Body": "ElasticMQ Test Message"
}
]
}
先ほど送ったメッセージを受信できましたね。
メッセージの削除
管理画面を確認すると、受信しただけではメッセージは削除されないようです。
以下のコマンドでメッセージを削除します。
aws sqs delete-message --queue-url http://localhost:9324/queue/test-queue --receipt-handle 65ba8f9b-3c22-4220-9e92-b0f5b469ef85#06e57300-cb75-45fb-ae7c-27b349179980 --endpoint-url http://localhost:9324
※ --receipt-handle
は先ほど受信したときの値を入力
削除されたことを管理画面で確認できました。
Lambdaで動作確認
では次は実際にLambdaからElasticMQにメッセージを送信してみましょう。
sam localを使って、ローカル実行させたLambdaからメッセージを送信してみます。
sam template
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sqs-test
Sample SAM Template for sqs-test
Parameters:
AwsEndpointSQSUrl:
Type: String
Default: ""
Globals:
Function:
Timeout: 10
Resources:
SQSTestFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: sqs-test/
Handler: app.lambdaHandler
Runtime: nodejs20.x
Architectures:
- x86_64
Environment:
Variables:
AWS_ENDPOINT_URL_SQS: !Ref AwsEndpointSQSUrl
AWS_ENDPOINT_URL_SQS
という環境変数にElasticMQのURLを渡してあげることで、コード上でendpointを指定せずにローカルのElasticMQと通信するように設定してあげています。
Lambdaのコード
import { SendMessageCommand, SQSClient } from "@aws-sdk/client-sqs";
const client = new SQSClient();
const SQS_QUEUE_URL = "http://elasticmq:9324/queue/test-queue";
export const lambdaHandler = async (event, context) => {
const command = new SendMessageCommand({
QueueUrl: SQS_QUEUE_URL,
MessageBody: "ElasticMQ Test Message on Lambda",
});
const response = await client.send(command);
console.log(response);
return response;
};
単純にメッセージを送信するだけの処理を作成しました。
SQS_QUEUE_URL
にはElasticMQに作成したキューのURLを渡しています。
※ localhostじゃないの?と思うかもしれませんが、sam localはコンテナ上で動作しているので、外部コンテナに接続するためにElasticMQのコンテナのホスト名を指定する必要があります。
実行してみよう
では先ほどのLambdaをローカルで実行してみましょう。
まずはsam build
して...
完了したら以下のコマンドで実行しましょう。
sam local invoke --parameter-overrides AwsEndpointSQSUrl=http://elasticmq:9324 --docker-network sam-local
--docker-network
で先ほど作ったdocker networkを指定しましょう。(指定しないとElasticMQへ通信できずエラーとなります。)
--parameter-overrides
では環境変数の値を渡しています。
実行してエラー無くレスポンスが返ってくれば、メッセージが送信できているはずです。
管理画面でメッセージが届いていることが確認できました!
では再度CLIでメッセージを受信してみましょう。
aws sqs receive-message --queue-url http://localhost:9324/queue/test-queue --endpoint-url http://localhost:9324
{
"Messages": [
{
"MessageId": "c33ed69a-63e7-40e3-addf-3aba9da37d2d",
"ReceiptHandle": "c33ed69a-63e7-40e3-addf-3aba9da37d2d#71b77844-5504-463d-9bfe-655827a10947",
"MD5OfBody": "d47936c65dcf06da701ae504dff350f3",
"Body": "ElasticMQ Test Message on Lambda"
}
]
}
無事、Lambdaから送信したメッセージを受信できました!
参考記事
Discussion