Les webhooks d'événements en temps réel de Bird sont un outil incroyablement précieux pour les expéditeurs afin d'avoir des données automatiquement envoyées à leurs systèmes. Cela peut mener à une automatisation en aval telle que la mise à jour des listes de diffusion, le déclenchement de parcours d'e-mails automatisés ou le peuplement de tableaux de bord internes. Bien que les mêmes données d'événements puissent être accessibles via l'interface utilisateur de Bird en utilisant Event Search, ou de manière programmatique en tirant parti de l'API Events de Bird, les limitations imposées sur le nombre d'enregistrements renvoyés dans une seule demande ou les limites de taux imposées sur le point de terminaison API peuvent rendre ces deux méthodes restrictives pour les expéditeurs grands et sophistiqués.
Les webhooks d'événements en temps réel permettent à un expéditeur de configurer un point de terminaison où Bird transmet les données, et les données peuvent être consommées sans avoir à programmer des tâches cron qui extraient les données. Il existe également des compromis logistiques lors du tirage des données par rapport à avoir les données poussées vers vous, comme devoir identifier la période de temps et les paramètres à utiliser pour chaque demande API. Si les périodes de temps ne sont pas parfaitement alignées, vous risquez de manquer des données, et si les périodes de temps se chevauchent, vous devez gérer des enregistrements de données en double. Avec les webhooks en temps réel, les données d'événements sont simplement poussées vers votre point de terminaison dès qu'elles deviennent disponibles au sein de Bird.
Bien que les avantages de recevoir des données d'événements en temps réel pour stimuler les processus d'automatisation en aval puissent être immédiatement compris par de nombreux expéditeurs, le processus réel pour mettre en œuvre et consommer des webhooks peut être intimidant. Cela peut être particulièrement vrai si vous n'êtes pas familier avec les composants techniques de la création d'un point de terminaison et du traitement des données de manière programmatique. Des services sont disponibles qui consommeront les données des webhooks de Bird et les transformeront en votre base de données automatiquement – un exemple serait StitchData, dont nous avons parlé dans le passé. Cependant, si vous souhaitez plus de contrôle sur le processus, vous pouvez facilement construire les composants vous-même. Ce qui suit est un guide simple pour aider les expéditeurs à se sentir à l'aise lors de la création d'un webhook d'événements Bird et de la consommation des données à l'aide de l'infrastructure au sein d'AWS.
Configuration du point de terminaison cible du webhook
Lorsque un événement Bird est créé, nous voulons que ces données d'événements soient diffusées en temps réel vers un point de terminaison dans AWS afin que nous puissions consommer et utiliser ces données de manière programmatique. Les données seront envoyées de Bird vers un point de terminaison cible, qui transmettra la charge utile à une fonction lambda qui traitera et stockera les données dans un compartiment S3. Un schéma haute niveau du flux de données décrit peut être vu ci-dessous :
Pour mettre en œuvre ce flux de travail, commençons par construire en ordre inverse en commençant par créer un compartiment S3 où nous allons stocker nos données d'événements, puis travailler à l'envers – en ajoutant chaque composant qui alimente ce que nous avons construit.
Créer un compartiment S3 pour stocker les données du webhook
Avant de créer notre équilibreur de charge pour accepter les données, ou notre fonction lambda pour stocker les données, nous devons d'abord créer notre compartiment S3 où les données seront stockées. Pour ce faire, naviguez vers le service S3 dans AWS et appuyez sur "Create Bucket". Vous serez invité à attribuer un nom à votre compartiment et à définir la région – assurez-vous d'utiliser la même région que votre ALB et votre fonction lambda. Lorsque votre compartiment S3 est créé, il sera vide – si vous souhaitez organiser les données à l'intérieur d'un dossier, vous pouvez soit créer le répertoire prévu maintenant, soit le répertoire sera créé lorsque votre fonction lambda stockera le fichier. Dans cet exemple, nous avons nommé notre compartiment S3 "bird-webhooks" et créé un dossier nommé "B Event Data" pour stocker nos données d'événements – vous verrez ces noms référencés dans notre fonction lambda ci-dessous.
Créer une fonction lambda pour consommer les données
Le traitement et le stockage réels des données seront effectués par une fonction lambda qui est invoquée par notre équilibreur de charge d'application (ALB).
La première étape consiste à créer votre fonction lambda en naviguant vers le service Lambda dans AWS et en cliquant sur "Create Function". Vous serez invité à attribuer un nom à votre fonction lambda et à sélectionner le langage de programmation dans lequel écrire votre fonction. Pour cet exemple, nous utilisons Python comme langage d'exécution.
Maintenant, nous devons développer notre fonction lambda. Pendant un moment, supposons que notre équilibreur de charge d'application a été configuré et transmet la charge utile du webhook à notre fonction lambda – la lambda recevra une charge utile comprenant tous les en-têtes et corps complets. La charge utile est passée dans notre fonction lambda en utilisant l'objet "event" comme un dictionnaire. Vous pouvez consulter les en-têtes et le corps de la charge utile indépendamment en accédant aux objets "headers" et "body" au sein de la charge utile. Dans cet exemple, nous allons simplement lire l'en-tête "x-messagesystems-batch-id", où l'ID de lot est une valeur unique créée par Bird pour le lot de webhook, et l'utiliser comme nom de fichier lors du stockage du corps en tant que fichier plat dans S3 ; cependant, vous voudrez peut-être ajouter d'autres fonctionnalités telles que des vérifications d'authentification ou la gestion des erreurs, selon les besoins.
Lors du stockage de la charge utile dans un fichier plat sur S3, nous devrons définir le nom du compartiment S3, l'emplacement et le nom de fichier où les données de la charge utile seront stockées. Dans notre fonction lambda d'exemple, nous le faisons dans la fonction "store_batch". Dans cet exemple, nous allons stocker l'ensemble du lot en tant que fichier unique, ce qui permet de garantir que les données sont collectées et stockées avant que la connexion HTTP entre Bird et votre point de terminaison ne se termine. Bien que vous puissiez ajuster les paramètres de délai d'attente de connexion sur votre équilibreur de charge, il n'y a aucune garantie que la connexion ne sera pas interrompue du côté de la transmission (dans ce cas, Bird) ou que la connexion ne sera pas résiliée avant que votre fonction lambda n'ait terminé son exécution. Il est recommandé de garder votre fonction consommatrice aussi efficace que possible et de réserver les activités de traitement des données pour les processus en aval lorsque cela est possible – par exemple, en convertissant la charge utile au format JSON en un fichier CSV, ou en chargeant les données d'événements dans une base de données.
Il est important de noter que vous devrez peut-être mettre à jour les autorisations pour votre fonction lambda. Votre rôle d'exécution aura besoin des autorisations PutObject et GetObject pour S3. Il est recommandé de faire respecter le principe du moindre privilège, donc je recommande de définir ces autorisations uniquement pour le compartiment S3 dans lequel les charges utiles des webhooks seront stockées.
Un exemple de notre fonction lambda consommatrice peut être trouvé ici.
En guise de note rapide sur l'ID de lot : Bird regroupera des événements dans une seule charge utile, où chaque lot peut contenir de 1 à 350 enregistrements d'événements ou plus. Le lot se verra attribuer un ID de lot unique, qui peut être utilisé pour visualiser le statut du lot en tirant parti de l'API Event Webhooks ou dans votre compte Bird en cliquant sur un flux de webhook et en sélectionnant "Batch Status". Dans le cas où une charge utile de webhook ne pourrait pas être livrée, comme lors d'un délai d'attente de connexion, Bird réessaiera le lot en utilisant le même ID de lot. Cela peut se produire lorsque votre fonction lambda s'exécute près du temps de trajet maximum de 10 secondes et est une raison pour optimiser la fonction consommatrice afin de réduire le temps d'exécution.
Pour gérer toutes les activités de traitement des données, je recommande de créer une fonction lambda séparée qui s'exécute chaque fois qu'un nouveau fichier est créé dans le compartiment S3 – de cette façon, le traitement des données est effectué de manière asynchrone à la transmission des données, et il n'y a aucun risque de perdre des données en raison d'une connexion résiliée. Je discute de la fonction lambda de traitement dans une section ultérieure.
Créer un équilibreur de charge d'application
Pour recevoir une charge utile de webhook, nous devons fournir un point de terminaison pour envoyer les charges utiles. Nous faisons cela en créant un équilibreur de charge d'application dans AWS en naviguant vers EC2 > Load Balancers et en cliquant sur "Create Load Balancer". Vous serez invité à choisir le type d'équilibreur de charge que vous souhaitez créer – pour cela, nous voulons créer un équilibreur de charge d'application. Nous devons utiliser un équilibreur de charge d'application (ALB) pour construire notre consommateur car les webhooks d'événements seront envoyés en tant que requête HTTP, et les ALB sont utilisés pour le routage des requêtes HTTP dans AWS. Nous pourrions mettre en œuvre une passerelle HTTP en alternative ; cependant, nous utilisons un ALB pour ce projet car il est plus léger et rentable qu'une passerelle HTTP. Il est important de noter que si vous choisissez d'utiliser une passerelle HTTP, le format de l'événement peut être différent de celui d'un ALB, et donc votre fonction lambda devra traiter l'objet de requête en conséquence.
Une fois que votre ALB a été créé, vous serez invité à attribuer un nom à votre ALB et à configurer le schéma et les paramètres d'accès/sécurité – puisque nous prévoyons de recevoir des données événementielles d'une source externe (Bird), nous voudrons que notre ALB soit orienté vers Internet. Sous "Listeners and routing", l'ALB doit écouter HTTPS sur le port 443, et nous voulons créer un groupe cible qui pointe vers notre fonction lambda afin que notre ALB transmette les demandes entrantes à la fonction lambda de consommation que nous avons créée ci-dessus. Vous devez également vous assurer que le groupe de sécurité a la permission d'accepter le trafic via le port 443.
Créer un enregistrement DNS pour l'équilibreur de charge
Pour faciliter l'utilisation de notre ALB en tant que point de terminaison, nous allons créer un enregistrement A dans DNS qui pointe vers notre ALB. Pour cela, nous pouvons utiliser le service AWS Route 53 (ou votre fournisseur DNS actuel) et créer un enregistrement A pour le nom d'hôte que vous souhaitez utiliser pour votre point de terminaison (par exemple, spevents.<your_domain>). L'enregistrement A doit être configuré pour pointer vers l'ALB que nous avons créé. Si vous utilisez Route 53 pour gérer les enregistrements DNS, vous pouvez référencer directement l'instance ALB en activant "Alias" et en sélectionnant l'ALB ; sinon, si vous utilisez un fournisseur DNS externe, vous devez pointer l'enregistrement A vers l'adresse IP publique de l'instance ALB.
Je recommande d'utiliser un outil tel que Postman pour tester que tout a été configuré correctement avant d'activer votre webhook Bird. Vous pouvez faire une requête POST à votre point de terminaison et confirmer qu'une réponse est reçue. Si votre requête POST ne renvoie pas de réponse, vous devrez peut-être vérifier que votre ALB écoute le bon port.
Créer un webhook Bird
Maintenant, nous sommes prêts à créer le webhook dans Bird et à utiliser le nom d'hôte défini par l'enregistrement A ci-dessus comme notre point de terminaison cible. Pour créer le webhook, naviguez vers la section Webhooks de votre compte Bird et cliquez sur "Create Webhook". Vous serez invité à attribuer un nom à votre webhook et à fournir une URL cible – la cible doit être le nom d'hôte de l'enregistrement A que vous avez créé précédemment. Notez que l'URL cible peut nécessiter l'inclusion de "HTTPS://" dans l'URL.
Une fois terminé, vérifiez que le sous-compte et les événements corrects sont sélectionnés, puis appuyez sur "Create Webhook" pour enregistrer votre configuration. Les données d'événements pour tous les types d'événements sélectionnés seront désormais diffusées vers notre URL cible et seront consommées par notre ALB pour un traitement en aval.
Traitement des données d'événements du webhook
En fonction de l'objectif prévu pour le stockage des données d'événements de Bird, vos besoins peuvent être satisfaits en stockant simplement la charge utile JSON sous forme de fichier plat. Vous pouvez également disposer d'un processus ETL en aval déjà établi capable de consommer et de charger des données au format JSON. Dans ces deux cas, vous pouvez peut-être utiliser le fichier plat créé par notre fonction lambda de traitement que nous avons créée ci-dessus tel quel.
Alternativement, vous aurez peut-être besoin de transformer les données – par exemple, pour convertir du JSON en un format CSV – ou charger les données directement dans une base de données. Dans cet exemple, nous allons créer une simple fonction lambda qui convertira les données du webhook du format JSON d'origine en un fichier CSV pouvant être chargé dans une base de données.
Créer une Lambda pour traiter les données
Comme pour la fonction lambda pour consommer les données du webhook, nous devons créer une nouvelle fonction lambda en naviguant vers le service Lambda dans AWS et en appuyant sur "Create Function". Cette nouvelle fonction lambda sera déclenchée lorsqu'un nouveau fichier est créé dans notre compartiment S3 – elle lira les données et les convertira en un nouveau fichier csv.
La fonction lambda accepte les informations sur le fichier en tant qu'événement. Dans l'exemple de fonction lambda, vous verrez que nous avons d'abord une série de vérifications de validation pour nous assurer que les données sont complètes et formatées comme prévu. Ensuite, nous convertissons la charge utile JSON en un fichier CSV en utilisant la bibliothèque "csv" et en écrivant dans un fichier temporaire. Les fonctions Lambda ne peuvent écrire des fichiers locaux que dans le répertoire "/tmp", donc nous créons un fichier csv temporaire et le nommons avec la convention <batch_id>.csv. La raison pour laquelle nous utilisons l'id de lot ici est simplement pour garantir que les processus parallèles qui s'exécutent en raison de la réception de plusieurs charges utiles de webhook ne s'interfèrent pas les uns avec les autres, chaque lot de webhook ayant un ID de lot unique.
Une fois que les données ont été entièrement converties en CSV, nous lisons les données CSV sous forme de flux d'octets, supprimons le fichier temporaire, et enregistrons les données CSV en tant que nouveau fichier sur S3. Il est important de noter qu'un compartiment S3 différent est nécessaire pour la sortie, sinon, nous risquons de créer une boucle récursive qui peut entraîner une utilisation accrue de lambda et des coûts accrus. Nous devrons identifier dans quel compartiment S3 et emplacement nous voulons que notre fichier CSV soit stocké au sein de notre fonction lambda. Suivez la même procédure que ci-dessus pour créer un nouveau compartiment S3 pour stocker notre fichier CSV.
Notez que le répertoire tmp est limité à 512 Mo d'espace, il est donc important que le fichier temporaire soit supprimé par la suite pour assurer un espace suffisant pour les exécutions futures. La raison pour laquelle nous utilisons un fichier temporaire, plutôt que d'écrire directement sur S3, est de simplifier la connexion à S3 en ayant une seule requête.
Tout comme pour la fonction lambda de consommation, vous devrez peut-être mettre à jour les autorisations pour votre fonction lambda de traitement. Cette fonction lambda nécessite que le rôle d'exécution ait des autorisations GetObject pour le compartiment S3 d'entrée, et PutObject et GetObject pour le compartiment S3 de sortie.
Un exemple de notre fonction lambda de traitement peut être trouvé ici.
Configurer une lambda pour s'exécuter lorsque de nouvelles données sont stockées sur S3
Maintenant que notre fonction lambda pour convertir le fichier du format JSON au format CSV a été créée, nous devons la configurer pour se déclencher lorsqu'un nouveau fichier est créé dans notre compartiment S3. Pour ce faire, nous devons ajouter un déclencheur à notre fonction lambda en ouvrant notre fonction lambda et en cliquant sur "Add Trigger" en haut de la page. Sélectionnez "S3" et fournissez le nom du compartiment S3 où les charges utiles brutes du webhook sont stockées. Vous avez également la possibilité de spécifier un préfixe et/ou un suffixe de fichier pour filtrer. Une fois les paramètres configurés, vous pouvez ajouter le déclencheur en cliquant sur "Add" en bas de la page. Maintenant, votre fonction lambda de traitement s'exécutera chaque fois qu'un nouveau fichier est ajouté à votre compartiment S3.
Charger les données dans une base de données
Dans cet exemple, je ne vais pas aborder le chargement des données dans une base de données en détail, mais si vous avez suivi cet exemple, vous avez quelques options :
Charger les données directement dans votre base de données au sein de votre fonction lambda de traitement
Consommer votre fichier CSV à l'aide d'un processus ETL établi
Que vous utilisiez un service de base de données AWS, tel que RDS ou DynamoDB, ou que vous ayez votre propre base de données PostgreSQL (ou similaire), vous pouvez vous connecter à votre service de base de données directement depuis votre fonction lambda de traitement. Par exemple, de la même manière que nous avons appelé le service S3 en utilisant "boto3" dans notre fonction lambda, vous pourriez également utiliser "boto3" pour appeler RDS ou DynamoDB. Le service AWS Athena pourrait également être utilisé pour lire les fichiers de données directement depuis les fichiers plats et accéder aux données à l'aide d'un langage de requête similaire au SQL. Je recommande de consulter la documentation respective pour le service que vous utilisez pour plus d'informations sur la meilleure façon de procéder dans votre environnement.
De même, il existe de nombreux services disponibles qui peuvent aider à consommer des fichiers CSV et à charger les données dans une base de données. Vous avez peut-être déjà un processus ETL établi que vous pouvez exploiter.
Nous espérons que ce guide vous a été utile - bonne envoi !