Une fonction qui attend des nouvelles
Un gestionnaire Lambda est une fonction qu’un service cloud appelle pour vous quand quelque chose arrive. Par exemple, une photo est déposée dans un bucket S3. La nouvelle arrive sous forme d’un dictionnaire appelé événement.
Dans ce module, vous écrivez le gestionnaire et vous le testez en l’appelant vous-même. Rien n’est déployé nulle part, et les événements sont inventés à la main.
À la fin de cette leçon
Remarque
Je peux écrire un gestionnaire qui lit un événement et renvoie un résultat.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Gestionnaire | la fonction que le service appelle | handler(event, context) |
| Événement | un dictionnaire qui décrit ce qui s’est passé | event |
| Enregistrement | un élément de la liste de nouvelles de l’événement | Record |
| Jeu d’essai | un événement inventé que l’on garde pour tester | |
| Idempotent | sans danger à exécuter deux fois, pour le même résultat |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un gestionnaire prend un événement et un contexte
Un gestionnaire est une fonction Python ordinaire à deux paramètres. event contient la nouvelle. context contient des faits sur la fonction qui tourne, comme le temps qu’elle a le droit de prendre.
La fonction renvoie un résultat. Comme ce n’est qu’une fonction, vous pouvez l’appeler vous-même avec un événement inventé.
Déployé nulle part
Remarque
Aucune fonction n’est envoyée dans ce module. Les formes d’événements ici sont celles que la documentation décrit pour une fonction, pas la sortie d’une pile que vous auriez déployée vous-même. Vous testez en appelant la fonction à la main.
Exécutez : appeler un gestionnaire à la main
evenement = {
"Records": [
{
"eventSource": "aws:s3",
"eventName": "ObjectCreated:Put",
"s3": {"bucket": {"name": "boutique-depots"}, "object": {"key": "images/chat.png", "size": 1024}},
}
]
}
def gestionnaire(event, context):
premier = event["Records"][0]
bucket = premier["s3"]["bucket"]["name"]
cle = premier["s3"]["object"]["key"]
return {"depose": bucket + "/" + cle}
print(gestionnaire(evenement, None))
# Remplacez la clé par images/chien.png et exécutez de nouveau.
Un événement contient une liste d’enregistrements
Un événement peut porter plusieurs enregistrements, donc un gestionnaire parcourt Records. Chacun dit d’où il vient dans eventSource.
Un enregistrement S3 nomme un bucket et une clé. Un enregistrement SQS, venu d’une file, a un body. Le corps est une chaîne, donc un corps JSON demande json.loads avant de pouvoir être lu.
Exemple travaillé : deux sortes d’enregistrements
| Champ | Enregistrement S3 | Enregistrement SQS |
|---|---|---|
| eventSource | aws:s3 | aws:sqs |
| Ce qui s’est passé | eventName, comme ObjectCreated:Put | un message dans body |
| Où regarder | s3.bucket.name et s3.object.key | body, une chaîne JSON |
| Un identifiant unique | aucun sur lequel compter | messageId |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Exécutez : lire les deux sortes d’enregistrements
import json
evenement = {"Records": [
{"eventSource": "aws:sqs", "messageId": "m-1", "body": "{\"commande\": 1, \"article\": \"thé\"}"},
{"eventSource": "aws:s3", "eventName": "ObjectCreated:Put",
"s3": {"bucket": {"name": "boutique-depots"}, "object": {"key": "journaux/web.log"}}},
]}
def gestionnaire(event, context):
vus = []
for enregistrement in event["Records"]:
if enregistrement["eventSource"] == "aws:sqs":
commande = json.loads(enregistrement["body"])
vus.append("commande " + str(commande["commande"]))
elif enregistrement["eventSource"] == "aws:s3":
vus.append("fichier " + enregistrement["s3"]["object"]["key"])
return vus
print(gestionnaire(evenement, None))
Une même nouvelle, deux fois
Une file promet une livraison au moins une fois. Le même message peut arriver deux fois à votre fonction, par exemple après une exécution lente.
Un gestionnaire est idempotent quand une deuxième exécution ne change rien. Gardez une note de ce qui est fini, et sautez tout travail déjà noté. Une vraie fonction garde cette note dans une table, et la leçon 9 en utilise une. Ici, un ensemble en tient lieu.
Erreur fréquente
Attention
Beaucoup croient que chaque message arrive une seule fois. Ce n’est pas vrai : la livraison est au moins une fois. Rendez le gestionnaire sûr à exécuter deux fois, sinon une commande est facturée deux fois.
Exécutez : sauter ce qui est déjà fait
def traiter(commandes, faites):
nouvelles = []
for commande in commandes:
if commande in faites:
continue
faites.add(commande)
nouvelles.append(commande)
return nouvelles
faites = set()
print(traiter([1, 2, 2], faites))
print(traiter([2, 3], faites))
# Ajoutez la commande 4 à la seconde liste. Que montre la seconde ligne affichée ?