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.