Serverless Frameworkを使ってAWS LambdaからAmazon SNSへメッセージを発行する処理を書いてみました。
AWS Lambdaの処理(test.js)
Amazon SNSへメッセージを発行する関数です。
発行先のTopicArnは環境変数から取得します。
'use strict';
const AWS = require('aws-sdk');
const sns = new AWS.SNS({apiVersion: '2010-03-31'});
const TOPIC_ARN = process.env.TOPIC_ARN;
module.exports.handler = async function(event, context) {
const params = {
Message: 'message',
Subject: 'subject',
TopicArn: TOPIC_ARN
};
return await sns.publish(params).promise();
};
serverless.ymlの定義
resourcesでAmazon SNSを定義しておくと、serverless deploy時にトピックやサブスクリプションを自動生成してくれます。
自動生成されたトピックのARNをprovider.environmentの環境変数(TOPIC_ARN)に格納していて、AWS LambdaはこのARNに対してメッセージを発行します。
Amazon SNSへメッセージが発行されると、サブスクリプションの宛先へメールが送信されます。
service: my-service provider: name: aws runtime: nodejs12.x region: us-east-1 stage: ${opt:stage, self:custom.defaultStage} profile: ${self:custom.profiles.${self:provider.stage}} iamRoleStatements: - Effect: Allow Action: - sns:Publish Resource: !Ref SNSTopic environment: TOPIC_ARN: !Ref SNSTopic custom: defaultStage: dev profiles: dev: serverless-dev prod: serverless-prod functions: test: handler: test.handler memorySize: 128 timeout: 3 resources: Resources: SNSTopic: Type: AWS::SNS::Topic Properties: DisplayName: SNS Topic TopicName: ${self:service}-${self:provider.stage}-topic SNSSubscription: Type: AWS::SNS::Subscription Properties: Endpoint: test@example.com Protocol: email TopicArn: !Ref SNSTopic
動作確認
deploy、invokeしてメールが受信できたら成功です。
> serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (378 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.......
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: us-east-1
stack: my-service-dev
resources: 8
api keys:
None
endpoints:
None
functions:
test: my-service-dev-test
layers:
None
Serverless: Removing old service artifacts from S3...
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
> serverless invoke -f test -l
null
--------------------------------------------------------------------
START RequestId: 7f5506a1-e3a0-4c48-b3e5-34a6b6e1f1de Version: $LATEST
END RequestId: 7f5506a1-e3a0-4c48-b3e5-34a6b6e1f1de
REPORT RequestId: 7f5506a1-e3a0-4c48-b3e5-34a6b6e1f1de Duration: 768.61 ms Billed Duration: 800 ms Memory Size: 128 MB Max Memory Used: 90 MB Init Duration: 382.09 ms
AuthorizationError
AWS LambdaにAmazon SNSへのアクセス権がないと下記のようなエラーが発生します。
serverless.ymlでiamRoleStatementsを追加してアクセスを許すと実行できるようになりました。
> serverless invoke -f test -l { "errorType": "AuthorizationError", "errorMessage": "User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic", "trace": [ "AuthorizationError: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic", " at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/query.js:50:29)", " at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)", " at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)", " at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)", " at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)", " at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)", " at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10", " at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)", " at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)", " at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)" ] } -------------------------------------------------------------------- START RequestId: 0338236e-835c-4160-be21-e5d3aec07734 Version: $LATEST 2020-03-22 11:14:46.076 (+09:00) 0338236e-835c-4160-be21-e5d3aec07734 ERROR Invoke Error {"errorType":"AuthorizationError","errorMessage":"User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic","code":"AuthorizationError","message":"User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic","time":"2020-03-22T02:14:46.075Z","requestId":"fce7bca4-e69c-525c-bee1-ea630b4a00d5","statusCode":403,"retryable":false,"retryDelay":14.81009541751066,"stack":["AuthorizationError: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic"," at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/query.js:50:29)"," at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)"," at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)"," at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)"," at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)"," at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)"," at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10"," at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)"," at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)"," at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"]} END RequestId: 0338236e-835c-4160-be21-e5d3aec07734 REPORT RequestId: 0338236e-835c-4160-be21-e5d3aec07734 Duration: 377.61 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 90 MB Error -------------------------------------------------- Error: Invoked function failed at AwsInvoke.log (C:\snapshot\serverless\lib\plugins\aws\invoke\index.js:105:31) at AwsInvoke.tryCatcher (C:\snapshot\serverless\node_modules\bluebird\js\release\util.js:16:23) at Promise._settlePromiseFromHandler (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:547:31) at Promise._settlePromise (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:604:18) at Promise._settlePromise0 (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:649:10) at Promise._settlePromises (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:729:18) at _drainQueueStep (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:93:12) at _drainQueue (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:86:9) at Async._drainQueues (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:102:5) at Immediate._onImmediate (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:15:14) at processImmediate (internal/timers.js:439:21) at process.topLevelDomainCallback (domain.js:130:23) For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable. Get Support -------------------------------------------- Docs: docs.serverless.com Bugs: github.com/serverless/serverless/issues Issues: forum.serverless.com Your Environment Information --------------------------- Operating System: win32 Node Version: 12.13.1 Framework Version: 1.63.0 (standalone) Plugin Version: 3.3.0 SDK Version: 2.3.0 Components Core Version: 1.1.2 Components CLI Version: 1.4.0