Filtrowanie zdarzeń wyzwalających Lambdę
Wczoraj AWS umożliwił filtrowanie zdarzeń pochodzących z usług SQS, DynamoDB oraz Kinesis, które wyzwalają wykonanie funkcji Lambda. Szkoda, że nie jakieś dwa tygodnie temu. Przydałoby się w jednym rozwiązaniu wdrożonym u klienta, gdzie filtrowanie zdarzeń wyzwalających Lambdę, a właściwie filtrowanie samych wiadomości, które były procesowane zaimplementowaliśmy wewnątrz funkcji.
To bardzo fajna możliwość. Pozwoli, w niektórych przypadkach dość znacząco, zmniejszyć koszty. Ponad to uprości implementację samych funkcji. Będzie w nich mniej warunków.
Przetestowałem to sobie, zobaczmy więc jak to wygląda.
Filtrowanie zdarzeń wyzwalających Lambdę
Na początek, za pomocą AWS SAM utworzyłem prosty stack składający się z funkcji Lambda, która będzie uruchamiana za pomocą eventów (wiadomości) z kolejki SQS.
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > events-filtering Globals: Function: Timeout: 5 Resources: Function: Type: AWS::Serverless::Function Properties: CodeUri: filtering/ Handler: app.lambda_handler Runtime: python3.8 Policies: - SQSPollerPolicy: QueueName: !GetAtt SqsQueue.QueueName Events: MySQSEvent: Type: SQS Properties: Queue: !GetAtt SqsQueue.Arn BatchSize: 1 SqsQueue: Type: AWS::SQS::Queue Outputs: Queue: Description: Queue URL Value: !Ref SqsQueue Lambda: Description: Lambda function name Value: !Ref Function
Sama funkcja nie robi nic, poza zapisaniem eventu do logu.
import json def lambda_handler(event, context): print(json.dumps(event))
Po wdrożeniu na koncie w AWS sam deploy --guided
dostałem adres URL do kolejki oraz nazwę samej funkcji. Przyda się to za chwilę.
Sprawdziłem w konsoli, moja kolejka była ustawiona jako trigger do funkcji.
Przygotowałem sobie dwa pliki z wiadomościami: sqs_event_ok.json oraz sqs_event_alarm.json. Ich zawartość była bardzo podobna, różniła się tylko wartością pola status.
{ "text": "Message 1", "status": "OK" }
{ "text": "Message 1", "status": "Alarm" }
Sprawdziłem czy wszystko działa jeszcze bez filtrowania wysyłając obie wiadomości do kolejki za pomocą poleceń aws sqs send-message --queue-url <QUEUE-URL> --message-body file://sqs_event_ok.json --region us-east-1
oraz aws sqs send-message --queue-url <QUEUE-URL> --message-body file://sqs_event_alarm.json --region us-east-1
.
A następnie sprawdziłem jak wygląda log funkcji Lambda sam logs -n <NAZWA_FUNKCJI_LAMBDA>
Jak widać, obie wiadomości poprawnie uruchomiły funkcję.
Filtr
Nasz filtr będzie wybierał z kolejki tylko wiadomości, które mają ustawione pole status na wartość Alarm. Dodajemy więc do definicji eventu wyzwalającego Lambdę kilka linijek
Events: MySQSEvent: Type: SQS Properties: Queue: !GetAtt SqsQueue.Arn BatchSize: 1 FilterCriteria: Filters: - Pattern: "{\"body\":{\"status\": [\"Alarm\"]}}"
i robimy deployment do chmury sam deploy
Więcej o składni samego filtrowania można przeczytać w dokumentacji.
Spróbujmy teraz wysłać wiadomość z wartością OK aws sqs send-message --queue-url <QUEUE-URL> --message-body file://sqs_event_ok.json --region us-east-1
i sprawdźmy szybko logi funkcji sam logs -n <NAZWA_FUNKCJI> -s '2min ago' --region us-east-1
. W moim przypadku, nic w tych logach się nie pojawiło, czyli wiadomość nie wyzwoliła funkcji. O to nam chodziło.
Sprawdźmy więc jak zachowa się nasze rozwiązanie w przypadku wiadomości ustawionej jako alarm. Wysyłamy wiadomość aws sqs send-message --queue-url <QUEUE-URL> --message-body file://sqs_event_alarm.json --region us-east-1
i sprawdzamy ponownie logi sam logs -n <NAZWA_FUNKCJI> -s '2min ago' --region us-east-1
Tym razem, jak widać, wiadomość wyzwoliła funkcję.
Podobne filtry można ustawić także podczas definiowania triggera w konsoli AWS. Będzie on miał jednak trochę zamienioną składnię. Jako filtr wystarczy wpisać:
Do każdego źrodła możemy dodać do 5 filtrów. Wtedy zgodność z którymkolwiek z nich spowoduje wyzwolenie funkcji.