Die Echtzeit- Event-Webhooks von Bird sind ein unglaublich wertvolles Werkzeug für Sender, um Daten automatisch an ihre Systeme zu übertragen. Dies kann downstream-Automatisierungen vorantreiben, wie das Aktualisieren von Mailinglisten, das Auslösen automatisierter E-Mail-Reisen oder das Befüllen interner Dashboards. Während dieselben Ereignisdaten über die Bird-Benutzeroberfläche mithilfe von Ereignissuche oder programmatisch über die Nutzung der Bird Events-API abgerufen werden können, können Einschränkungen hinsichtlich der Anzahl der in einer einzelnen Anfrage zurückgegebenen Datensätze oder Rate-Limits, die auf den API-Endpunkt angewendet werden, beide Methoden für große und anspruchsvolle Sender einschränken.
Echtzeit-Event-Webhooks ermöglichen es einem Sender, einen Endpunkt zu konfigurieren, an den Bird die Daten überträgt, sodass die Daten konsumiert werden können, ohne Cron-Jobs planen zu müssen, die die Daten abrufen. Es gibt auch logistische Kompromisse beim Abrufen der Daten im Vergleich dazu, die Daten an sich übertragen zu lassen, wie die Identifizierung des Zeitraums und der Parameter, die für jede API-Anfrage verwendet werden sollen. Wenn die Zeiträume nicht perfekt aufeinander abgestimmt sind, riskieren Sie, Daten zu verpassen, und wenn sich die Zeiträume überschneiden, müssen Sie doppelte Datensätze verwalten. Mit Echtzeit-Webhooks werden Ereignisdaten einfach an Ihren Endpunkt übertragen, sobald sie innerhalb von Bird verfügbar sind.
Während die Vorteile des Erhaltens von Ereignisdaten in Echtzeit zur Steuerung downstream-Automatisierungsprozesse von vielen Sendern sofort erkannt werden, kann der tatsächliche Prozess zur Implementierung und Nutzung von Webhooks einschüchternd sein. Dies kann besonders zutreffen, wenn Sie nicht mit den technischen Komponenten der Erstellung eines Endpunkts und dem Umgang mit den Daten programmatisch vertraut sind. Es gibt Dienste, die Bird-Webhook-Daten konsumieren und automatisiert in Ihre Datenbank ETL – ein Beispiel wäre StitchData, über den wir in der Vergangenheit gebloggt haben. Wenn Sie jedoch mehr Kontrolle über den Prozess wünschen, können Sie die Komponenten auch selbst einfach erstellen. Folgendes ist eine einfache Anleitung, um Senders ein komfortables Gefühl bei der Erstellung eines Bird-Event-Webhooks und dem Konsumieren der Daten mit der Infrastruktur innerhalb von AWS zu geben.
Webhook-Zielendpunkt konfigurieren
Wenn ein Bird-Event erstellt wird, möchten wir, dass die Ereignisdaten in Echtzeit an einen Endpunkt in AWS gestreamt werden, damit wir diese Daten programmatisch konsumieren und verwenden können. Die Daten werden von Bird an einen Zielendpunkt gesendet, der die Payload an eine Lambda-Funktion weiterleitet, die die Daten verarbeitet und in einem S3-Bucket speichert. Ein hochrangiges Diagramm des beschriebenen Datenflusses ist unten zu sehen:
Um diesen Workflow zu implementieren, lassen Sie uns diese tatsächlich in umgekehrter Reihenfolge erstellen, beginnend mit der Erstellung eines S3-Buckets, in dem wir unsere Ereignisdaten speichern, und dann rückwärts arbeiten – indem wir jede Komponente hinzufügen, die in das einfließt, was wir erstellt haben.
Einen S3-Bucket erstellen, um die Webhook-Daten zu speichern
Bevor wir unseren Load Balancer erstellen, um die Daten zu akzeptieren, oder unsere Lambda-Funktion, um die Daten zu speichern, müssen wir zunächst unseren S3-Bucket erstellen, in dem die Daten gespeichert werden. Um dies zu tun, navigieren Sie zu dem S3-Dienst innerhalb von AWS und drücken "Bucket erstellen." Sie werden aufgefordert, Ihrem Bucket einen Namen zuzuweisen und die Region festzulegen – stellen Sie sicher, dass Sie dieselbe Region wie Ihren ALB und Ihre Lambda-Funktion verwenden. Wenn Ihr S3-Bucket erstellt wird, wird er leer sein – wenn Sie die Daten innerhalb eines Ordners organisieren möchten, können Sie entweder jetzt das beabsichtigte Verzeichnis erstellen oder das Verzeichnis wird erstellt, wenn Ihre Lambda-Funktion die Datei speichert. In diesem Beispiel haben wir unseren S3-Bucket "bird-webhooks" genannt und einen Ordner namens "B Event Data" erstellt, um unsere Ereignisdaten zu speichern – diese Namen werden in unserer Lambda-Funktion weiter unten erwähnt.
Eine Lambda-Funktion erstellen, um die Daten zu konsumieren
Die tatsächliche Verarbeitung und Speicherung der Daten erfolgt durch eine Lambda-Funktion, die von unserem Application Load Balancer (ALB) aufgerufen wird.
Der erste Schritt besteht darin, Ihre Lambda-Funktion zu erstellen, indem Sie zum Lambda-Dienst innerhalb von AWS navigieren und auf "Funktion erstellen" klicken. Sie werden aufgefordert, Ihrer Lambda-Funktion einen Namen zuzuweisen und auszuwählen, in welcher Programmiersprache Sie Ihre Funktion schreiben möchten. Für dieses Beispiel verwenden wir Python als Laufzeit-Programmiersprache.
Nun müssen wir unsere Lambda-Funktion entwickeln. Lassen Sie uns einen Moment annehmen, dass unser Application Load Balancer konfiguriert wurde und die Webhook-Payload an unsere Lambda-Funktion weiterleitet – die Lambda erhält eine Payload, die die vollständigen Header und den Body enthält. Die Payload wird in unsere Lambda-Funktion über das Objekt „event“ als Wörterbuch übergeben. Sie können unabhängig auf die Header und den Body der Payload zugreifen, indem Sie die Objekte „headers“ und „body“ innerhalb der Payload ansprechen. In diesem Beispiel werden wir einfach den Header „x-messagesystems-batch-id“ lesen, wobei die Batch-ID ein eindeutiger Wert ist, der von Bird für die Webhook-Batch erstellt wird, und ihn als Dateinamen verwenden, wenn wir den Body als Flachdatei in S3 speichern; jedoch möchten Sie möglicherweise zusätzliche Funktionen hinzufügen, wie z. B. Authentifizierungsprüfungen oder Fehlerbehandlung, nach Bedarf.
Beim Speichern der Payload in einer Flachdatei auf S3 müssen wir den Namen des S3-Buckets, den Speicherort und den Dateinamen der Datei definieren, in der die Payload-Daten gespeichert werden. In unserer Beispiel-Lambda-Funktion tun wir dies in der Funktion „store_batch“. In diesem Beispiel werden wir die gesamte Batch als einzelne Datei speichern, was dazu beiträgt, sicherzustellen, dass die Daten gesammelt und gespeichert werden, bevor die HTTP-Verbindung zwischen Bird und Ihrem Endpunkt abläuft. Obwohl Sie die Verbindungs-Timeout-Einstellungen Ihres Load Balancers anpassen könnten, gibt es keine Garantie, dass die Verbindung auf der Übertragungsseite (in diesem Fall Bird) nicht abläuft oder dass die Verbindung nicht beendet wird, bevor Ihre Lambda-Funktion ihre Ausführung beendet. Es ist eine bewährte Praxis, Ihre Verbraucherfunktion so effizient wie möglich zu gestalten und Datenverarbeitungsaktivitäten nach Möglichkeit für downstream-Prozesse zu reservieren – wie das Konvertieren der batchweise JSON-formatierten Payload in eine CSV-Datei oder das Laden der Ereignisdaten in eine Datenbank.
Es ist wichtig zu beachten, dass Sie möglicherweise die Berechtigungen für Ihre Lambda-Funktion aktualisieren müssen. Ihre Ausführungsrolle benötigt PutObject- und GetObject-Berechtigungen für S3. Es ist eine bewährte Praxis, das Prinzip des geringsten Privilegs durchzusetzen, daher empfehle ich, diese Berechtigungen nur für den S3-Bucket festzulegen, in dem die Webhook-Payloads gespeichert werden.
Ein Beispiel für unsere Verbraucher-Lambda-Funktion finden Sie hier.
Eine kurze Notiz zur Batch-ID: Bird wird Batch-Ereignisse in eine einzelne Payload, wobei jede Batch 1 bis 350 oder mehr Ereignisdatensätze enthalten kann. Die Batch erhält eine eindeutige Batch-ID, die verwendet werden kann, um den Batch-Status über die Event Webhooks API oder in Ihrem Bird-Konto zu sehen, indem Sie auf einen Webhook-Stream klicken und „Batch-Status“ auswählen. Im Falle, dass eine Webhook-Payload nicht zugestellt werden konnte, wie während eines Verbindungs-Timeouts, wird Bird die Batch automatisch wiederholen und dabei dieselbe Batch-ID verwenden. Dies kann passieren, wenn Ihre Lambda-Funktion nahe der maximalen Rundlaufzeit von 10 Sekunden ausgeführt wird und ist ein Grund, die Verbraucherfunktion zu optimieren, um die Ausführungszeit zu reduzieren.
Um alle Datenverarbeitungsaktivitäten zu behandeln, empfehle ich, eine separate Lambda-Funktion zu erstellen, die ausgeführt wird, wann immer eine neue Datei im S3-Bucket erstellt wird – so werden die Datenverarbeitungen asynchron zur Übertragung der Daten durchgeführt und es besteht kein Risiko, Daten aufgrund einer beendeten Verbindung zu verlieren. Ich bespreche die Verarbeitungs-Lambda-Funktion in einem späteren Abschnitt.
Erstellen eines Application Load Balancers
Um eine Webhook-Payload zu empfangen, müssen wir einen Endpunkt bereitstellen, an den die Payloads gesendet werden sollen. Dies tun wir, indem wir innerhalb von AWS einen Application Load Balancer erstellen, indem wir zu EC2 > Load Balancers navigieren und auf "Load Balancer erstellen" klicken. Sie werden aufgefordert, auszuwählen, welchen Typ von Load Balancer Sie erstellen möchten – dafür möchten wir einen Application Load Balancer erstellen. Wir müssen einen Application Load Balancer (ALB) verwenden, um unseren Verbraucher zu erstellen, da die Event-Webhooks als HTTP-Anfrage gesendet werden, und ALBs werden für das Routing von HTTP-Anfragen innerhalb von AWS verwendet. Wir könnten als Alternative einen HTTP-Gateway implementieren; jedoch verwenden wir für dieses Projekt einen ALB, da er leichter und kostengünstiger als ein HTTP-Gateway ist. Es ist wichtig zu beachten, dass wenn Sie sich entscheiden, einen HTTP-Gateway zu verwenden, das Ereignisformat von dem mit einem ALB abweichen kann, und daher muss Ihre Lambda-Funktion das Anforderungsobjekt entsprechend behandeln.
Sobald Ihr ALB erstellt wurde, werden Sie aufgefordert, ihm einen Namen zuzuweisen und das Schema sowie die Zugriffs-/Sicherheitseinstellungen zu konfigurieren – da wir planen, Ereignisdaten von einer externen Quelle (Bird) zu empfangen, möchten wir, dass unser ALB internetfähig ist. Unter „Listener und Routing“ sollte der ALB HTTPS auf Port 443 anhören, und wir möchten eine Zielgruppe erstellen, die auf unsere Lambda-Funktion zeigt, damit unser ALB eingehende Anfragen an die verbrauchende Lambda-Funktion weiterleitet, die wir oben erstellt haben. Sie müssen auch sicherstellen, dass die Sicherheitsgruppe die Erlaubnis hat, Verkehr über Port 443 zu akzeptieren.
Erstellen eines DNS-Eintrags für den Load Balancer
Um es uns einfacher zu machen, unseren ALB als Endpunkt zu nutzen, erstellen wir einen A-Eintrag im DNS, der auf unseren ALB zeigt. Dazu können wir den AWS Route 53-Dienst (oder Ihren aktuellen DNS-Anbieter) verwenden und einen A-Eintrag für den Hostnamen erstellen, den Sie für Ihren Endpunkt verwenden möchten (z. B. spevents.<your_domain>). Der A-Eintrag sollte so konfiguriert werden, dass er auf den ALB zeigt, den wir erstellt haben. Wenn Sie Route 53 verwenden, um die DNS-Einträge zu verwalten, können Sie die ALB-Instanz direkt referenzieren, indem Sie „Alias“ aktivieren und den ALB auswählen; andernfalls, wenn Sie einen externen DNS-Anbieter verwenden, sollten Sie den A-Eintrag auf die öffentliche IP-Adresse der ALB-Instanz verweisen.
Ich empfehle die Verwendung eines Tools wie Postman, um zu testen, ob alles korrekt konfiguriert wurde, bevor Sie Ihren Bird-Webhooks aktivieren. Sie können eine POST-Anfrage an Ihren Endpunkt stellen und bestätigen, dass eine Antwort erhalten wird. Wenn Ihre POST-Anfrage keine Antwort zurückgibt, müssen Sie möglicherweise überprüfen, ob Ihr ALB auf dem richtigen Port hört.
Erstellen eines Bird-Webhooks
Jetzt sind wir bereit, den Webhook in Bird zu erstellen und den oben definierten Hostnamen des A-Eintrags als unseren Zielendpunkt zu verwenden. Um den Webhook zu erstellen, navigieren Sie zum Webhook-Bereich innerhalb Ihres Bird-Kontos und klicken Sie auf „Webhook erstellen.“ Sie werden aufgefordert, einen Namen für Ihren Webhook zuzuweisen und eine Ziel-URL bereitzustellen – das Ziel sollte der Hostname des zuvor erstelle A-Eintrags sein. Beachten Sie, dass die Ziel-URL möglicherweise „HTTPS://“ in der URL erfordert.
Nachdem Sie dies abgeschlossen haben, vergewissern Sie sich, dass das richtige Unterkonto und die Ereignisse ausgewählt sind, und drücken Sie „Webhook erstellen“, um Ihre Konfiguration zu speichern. Die Ereignisdaten für alle ausgewählten Ereignistypen werden nun an unsere Ziel-URL gestreamt und von unserem ALB für die downstream-Verarbeitung konsumiert.
Verarbeiten von Webhook-Ereignisdaten
Je nach beabsichtigtem Zweck der Speicherung der Bird-Ereignisdaten können Ihre Anforderungen möglicherweise bereits durch die bloße Speicherung der JSON-Payload als Flachdatei erfüllt werden. Möglicherweise haben Sie auch bereits einen downstream-ETL-Prozess eingerichtet, der in der Lage ist, Daten im JSON-Format zu konsumieren und zu laden. In beiden Fällen können Sie möglicherweise die von unserer Verarbeitungs-Lambda-Funktion erzielte Flachdatei so verwenden, wie sie ist.
Alternativ müssen Sie möglicherweise die Daten transformieren – beispielsweise um von einem JSON- ins CSV-Format zu konvertieren – oder die Daten direkt in eine Datenbank laden. In diesem Beispiel erstellen wir eine einfache Lambda-Funktion, die die Webhook-Daten vom ursprünglichen JSON-Format in eine CSV-Datei konvertiert, die in eine Datenbank geladen werden könnte.
Eine Lambda-Funktion zur Verarbeitung der Daten erstellen
Wie bei der Lambda-Funktion zum Konsumieren der Webhook-Daten müssen wir eine neue Lambda-Funktion erstellen, indem wir zum Lambda-Dienst innerhalb von AWS navigieren und auf „Funktion erstellen“ klicken. Diese neue Lambda-Funktion wird ausgelöst, wenn eine neue Datei in unserem S3-Bucket erstellt wird – sie wird die Daten lesen und in eine neue CSV-Datei konvertieren.
Die Lambda-Funktion akzeptiert die Dateiinformationen als Ereignis. In der Beispiel-Lambda-Funktion sehen Sie, dass wir zuerst eine Reihe von Validierungsprüfungen haben, um sicherzustellen, dass die Daten vollständig und wie erwartet formatiert sind. Anschließend konvertieren wir die JSON-Payload in eine CSV-Datei, indem wir die „csv“-Bibliothek verwenden und in eine temporäre Datei schreiben. Lambda-Funktionen können lokale Dateien nur im Verzeichnis “/tmp” speichern, daher erstellen wir eine temporäre CSV-Datei und benennen sie mit der Konvention <batch_id>.csv. Der Grund, warum wir hier die batch_id verwenden, besteht einfach darin, sicherzustellen, dass parallele Prozesse, die als Ergebnis des Empfangs mehrerer Webhook-Payloads ausgeführt werden, sich nicht gegenseitig beeinträchtigen, da jede Webhook-Batch eine eindeutige batch_id hat.
Sobald die Daten vollständig in CSV konvertiert wurden, lesen wir die CSV-Daten als Byte-Stream, löschen die temporäre Datei und speichern die CSV-Daten als neue Datei auf S3. Es ist wichtig zu beachten, dass ein anderer S3-Bucket für die Ausgabe benötigt wird, andernfalls riskieren wir, eine rekursive Schleife zu erzeugen, die zu einer erhöhten Lambda-Nutzung und damit zu höheren Kosten führen kann. Wir müssen identifizieren, in welchem S3-Bucket und an welchem Ort wir unsere CSV-Datei innerhalb unserer Lambda-Funktion speichern möchten. Folgen Sie demselben Verfahren wie oben, um einen neuen S3-Bucket zu erstellen, um unsere CSV-Datei zu speichern.
Beachten Sie, dass das tmp-Verzeichnis auf 512 MB Speicherplatz beschränkt ist, sodass es wichtig ist, dass die temporäre Datei anschließend gelöscht wird, um ausreichend Platz für zukünftige Ausführungen sicherzustellen. Der Grund, warum wir eine temporäre Datei verwenden, anstatt direkt in S3 zu schreiben, besteht darin, die Verbindung zu S3 durch eine einzige Anfrage zu vereinfachen.
Wie bei der Consumer-Lambda-Funktion müssen Sie möglicherweise die Berechtigungen für Ihre Verarbeitungs-Lambda-Funktion aktualisieren. Diese Lambda-Funktion erfordert, dass die Ausführungsrolle über GetObject-Berechtigungen für den Eingabe-S3-Bucket und sowohl PutObject- als auch GetObject-Berechtigungen für den Ausgabe-S3-Bucket verfügt.
Ein Beispiel für unsere Verarbeitungs-Lambda-Funktion finden Sie hier.
Konfigurieren einer Lambda-Funktion, die ausgeführt wird, wenn neue Daten in S3 gespeichert werden
Jetzt, da unsere Lambda-Funktion erstellt wurde, um die Datei vom JSON- in das CSV-Format zu konvertieren, müssen wir sie so konfigurieren, dass sie ausgelöst wird, wenn eine neue Datei in unserem S3-Bucket erstellt wird. Dazu müssen wir einen Trigger zu unserer Lambda-Funktion hinzufügen, indem wir unsere Lambda-Funktion öffnen und auf „Trigger hinzufügen“ oben auf der Seite klicken. Wählen Sie „S3“ aus und geben Sie den Namen des S3-Buckets an, in dem die Roh-Webhooks-Payloads gespeichert sind. Sie haben auch die Möglichkeit, ein Dateipräfix und/oder ein Suffix anzugeben, um zu filtern. Sobald die Einstellungen konfiguriert sind, können Sie den Trigger hinzufügen, indem Sie auf „Hinzufügen" am unteren Ende der Seite klicken. Jetzt wird Ihre Verarbeitungs-Lambda-Funktion ausgeführt, wann immer eine neue Datei in Ihren S3-Bucket hinzugefügt wird.
Daten in eine Datenbank laden
In diesem Beispiel werde ich nicht ausführlich auf das Laden der Daten in eine Datenbank eingehen, aber wenn Sie dieses Beispiel befolgt haben, haben Sie einige Optionen:
Laden Sie die Daten direkt in Ihre Datenbank innerhalb Ihrer Verarbeitungs-Lambda-Funktion.
Konsumieren Sie Ihre CSV-Datei mit einem etablierten ETL-Prozess.
Ob Sie einen AWS-Datenbankdienst wie RDS oder DynamoDB verwenden oder eine eigene PostgreSQL-Datenbank (oder ähnliches) haben, Sie können von Ihrer Verarbeitungs-Lambda-Funktion direkt eine Verbindung zu Ihrem Datenbankdienst herstellen. Beispielsweise könnten Sie ebenso wie wir den S3-Dienst mit „boto3“ in unserer Lambda-Funktion aufgerufen haben, auch „boto3“ verwenden, um RDS oder DynamoDB aufzurufen. Der AWS Athena-Dienst könnte ebenfalls verwendet werden, um die Daten Dateien direkt aus den Flachdateien zu lesen und die Daten mit einer Abfragesprache ähnlich wie SQL zuzugreifen. Ich empfehle, die jeweilige Dokumentation für den Dienst, den Sie verwenden, zu konsultieren, um weitere Informationen zu erhalten, wie Sie dies in Ihrer Umgebung am besten umsetzen können.
Ähnlich gibt es viele Dienste, die helfen können, CSV-Dateien zu konsumieren und die Daten in eine Datenbank zu laden. Möglicherweise haben Sie bereits einen etablierten ETL-Prozess, den Sie nutzen können.
Wir hoffen, dass Sie diesen Leitfaden hilfreich fanden – viel Erfolg beim Versenden!