SNSからLambdaを呼び出す
以下のページでSNSについて取り上げました。
上記のページでは、サブスクライバーとしてメールアドレスを指定しました。
今回はサブスクライバーにLambda関数を指定する方法を確認します。
構築する環境
構成は冒頭にご紹介したページと概ね同様です。
Lambda関数2からSNSトピックにメッセージを送信します。
つまりこの関数はパブリッシャーとして動作します。
この関数の働きは、現在日時からUNIX時間を取得し、メッセージとしてこれを送信します。
SNSトピックのサブスクライバーとしてLambda関数1を指定します。
この関数の働きは、メッセージとして渡されたUNIX時間が偶数/奇数か判定します。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/blob/main/100/fa-100.yaml
テンプレートファイルのポイント解説
(参考)Lambda関数でSNSにパブリッシュする
Resources:
Function2:
Type: AWS::Lambda::Function
Properties:
Architectures:
- !Ref Architecture
Environment:
Variables:
REGION: !Ref AWS::Region
TOPIC: !Ref TopicArn
Code:
ZipFile: |
import boto3
import datetime
import os
import time
topic = os.environ['TOPIC']
region = os.environ['REGION']
client = boto3.client('sns', region_name=region)
def lambda_handler(event, context):
now = datetime.datetime.now()
now_str = now.strftime('%Y-%m-%d %H:%M:%S.%f')
unix_time = str(time.mktime(now.timetuple()))
print(now_str, unix_time)
response = client.publish(
TopicArn=topic,
Subject=now_str,
Message=unix_time
)
print(response)
FunctionName: !Sub "${Prefix}-function-02"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole2.Arn
FunctionRole2:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: SNSPublishPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- sns:Publish
Resource:
- !Ref TopicArn
Code language: YAML (yaml)
Lambda関数からSNSにメッセージをパブリッシュします。
詳細は冒頭でご紹介したページをご確認ください。
なおCloudFormationでLambda関数を作成する方法については、以下のページをご確認ください。
今回はインラインで実行するコードを記載します。
SNSサブスクライバーにLambda関数を指定する
Resources:
Topic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: !Ref FunctionArn1
Protocol: lambda
TopicName: !Ref Prefix
Code language: YAML (yaml)
Subscriptionプロパティでサブスクライバーを設定します。
今回はLambda関数でSNSメッセージを受け取りますから、Endpointプロパティに関数のARNを、Protocolプロパティに「lambda」を指定します。
サブスクライバーにLambda関数を指定する場合、内部的にはSNSが関数を呼び出すという挙動になります。
そのためSNSに関数を呼び出す権限を与える必要があります。
Resources:
SNSPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref Function1
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref Topic
Code language: YAML (yaml)
以下のAWS公式ページを参考にして設定しました。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-subscribe-sns-topic-same-account/
Lambda関数でSNSメッセージを受け取る
Resources:
Function1:
Type: AWS::Lambda::Function
Properties:
Architectures:
- !Ref Architecture
Code:
ZipFile: |
def lambda_handler(event, context):
subject = event['Records'][0]['Sns']['Subject']
message = event['Records'][0]['Sns']['Message']
print(subject, message)
unix_time = int(float(message))
if (unix_time % 2) == 0:
print('{int} is even !'.format(int=unix_time))
else:
print('{int} is odd !'.format(int=unix_time))
FunctionName: !Sub "${Prefix}-function-01"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole1.Arn
Code language: YAML (yaml)
eventオブジェクト内に、SNSから発信されたメッセージが格納されています。
今回は受け取ったUNIX時間の偶数/奇数を判定します。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- SNSトピック:fa-100
- Lambda関数2:fa-100-function-02
- Lambda関数1:fa-100-function-01
作成されたリソースをAWS Management Consoleから確認します。
SNSトピックを確認します。
正常にSNSトピックが作成されていることがわかります。
そしてLambda関数1がサブスクライバーとして登録されていることもわかります。
Lambda関数を確認します。
2つの関数も正常に作成されていることがわかります。
関数1に注目すると、SNSからの呼び出しが許可されていることもわかります。
動作確認
1回目
準備が整いましたので、関数2を実行します。
関数2のTestタブから「Test」をクリックして実行します。
関数が正常に実行されたことがわかります。
現在日時からUNIX時間が計算されて、それをSNSメッセージとして発信したことがわかります。
今回のUNIX時間は「1669204672」でした。
続いて関数1のログを確認します。
関数が実行された形跡があります。
つまりパブリッシャーである関数2からSNSメッセージが発行されたことによって、サブスクライバーである関数1が自動的に呼び出されたということです。
UNIX時間の偶数/奇数判定の結果、「1669204672 is even !」が出力されました。
2回目
もう一度、同じ操作を行います。
以下が両関数の実行ログです。
今度は関数2でUNIX時間「1669204701」を持つSNSメッセージが発信されました。
これを受けて自動的に関数1が実行され、奇数と判定されて「1669204701 is odd !」が出力されました。
まとめ
SNSサブスクライバーにLambda関数を指定する方法を確認しました。