21 kwietnia 2021 roku, 00:40, minęła właśnie chyba druga godzina jak ja probuję zmusić funkcję lambda do wykonania się przez notyfikację topica SNSa. Niby trywialne zadanie i dokumentacja Serverlessa ma opisany ten use case:
functions:
dispatcher:
handler: dispatcher.dispatch
events:
- sns:
arn: !Ref SuperTopic
topicName: MyCustomTopic
resources:
Resources:
SuperTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: MyCustomTopic
Ale, niestety to nie dzialą. Metodą prób i błędów doszedłem do wniosku, że owszem ten events
- sns
działa, ale tylko jeśli zdefiniujemy tam nowy topic SNS. Jak wskazujemy jeszcze nieistniejący topic, to Serverless wypluwa do CloudFormation następujące instrukcje:
send-email:
handler: src/handler.sendEmail
memorySize: 128
timeout: 60
events:
- sns: asd # nowy topic do stworzenia przez CloudFormation
a to jest część szablonu CloudFormation wygenerowany przez Serverless dla konfiguracji wyżej:
"SNSTopicAsd": {
"Type": "AWS::SNS::Topic",
"Properties": {
"TopicName": "asd",
"Subscription": [
{
"Endpoint": {
"Fn::GetAtt": ["SendDashemailLambdaFunction", "Arn"]
},
"Protocol": "lambda"
}
]
}
},
"SendDashemailLambdaPermissionAsdSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": ["SendDashemailLambdaFunction", "Arn"]
},
"Action": "lambda:InvokeFunction",
"Principal": "sns.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{ "Ref": "AWS::Partition" },
":sns:",
{ "Ref": "AWS::Region" },
":",
{ "Ref": "AWS::AccountId" },
":",
"asd"
]
]
}
}
},
Natomiast, gdy chcemy wskazać już istniejący topic, to takich instrukcji w skrypcie CloudFormaiton brak:
send-email:
handler: src/handler.sendEmail
memorySize: 128
timeout: 60
events:
- sns:
arn: !Ref "DocumentGeneratedTopic" # ref do SNS topic zdefiniowanego w resources
topicName: edoc-generated
po prawiej stronie widać różnicę pomiędzy tworzeniem przez Serverless topica SNS i subskrypcji do niego przez funkcję Lambda i wskazaniem przez referencję już istniejącego topica
Niestety, ślepo uwierzyłem dokumentacji Serverlessa i przez godzinę lub dwie próbowałem rozkminić dlaczego to nie działa mimo że powinno, i rozwiązanie problemu powstało dopiero po analizie szablonów CloudFormation generowanych przez Serverless:
functions:
send-email:
handler: src/handler.sendEmail
memorySize: 128
timeout: 60
resources:
Resources:
DocumentGeneratedTopicSendEmailFunctionSubscription:
Type: AWS::SNS::Subscription
Properties:
Endpoint: "arn:aws:lambda:${self:provider.region}:#{AWS::AccountId}:function:${self:service}-${self:provider.stage}-send-email"
Protocol: lambda
TopicArn: !Ref "DocumentGeneratedTopic"
DocumentGeneratedTopicSendEmailFunctionInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref "DocumentGeneratedTopic"
FunctionName: "arn:aws:lambda:${self:provider.region}:#{AWS::AccountId}:function:${self:service}-${self:provider.stage}-send-email"
Zasadę ograniczonego zaufania, oprócz dróg publicznych, warto też stosować do dokumentacji technicznej.
WŁADYSŁAW CZYŻEWSKI, 21 KWIETNIA 2021 ROKU