La file de la cantine
À la cantine, il y a une seule file. Un élève arrive au bout, et le serveur prend celui qui est devant.
Une file SQS fait pareil avec des messages. Une boutique y dépose chaque nouvelle commande, et un travailleur les prend une par une. Cette leçon suit un message de l’envoi jusqu’à la suppression.
À la fin de cette leçon
Remarque
Je peux dire ce qui arrive à un message, de l’envoi à la suppression.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| File | une suite de messages qui attendent d’être traités | |
| Message | un morceau de texte qui attend dans une file | |
| Recevoir | demander à la file des messages à traiter | |
| Délai de visibilité | la durée pendant laquelle un message reçu reste caché | |
| Poignée de réception | le ticket qui permet de supprimer un message reçu | ReceiptHandle |
| Au moins une fois | un message peut arriver deux fois, mais il arrive toujours au moins une fois |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un receive vous donne un message
send_message met du texte dans la file. Sa réponse contient un MessageId. receive_message demande des messages. Sa réponse contient une liste nommée Messages.
Chaque message a un Body, le texte, et un ReceiptHandle. Un corps n’est que du texte. Beaucoup de boutiques y mettent du JSON, que le travailleur retransforme en dictionnaire avec json.loads.
Exemple travaillé : une réponse receive
| Champ | Ce qu’il contient | Exemple |
|---|---|---|
| Messages | une liste, un dictionnaire par message | deux messages |
| MessageId | l’identifiant donné par la file à l’envoi | m-1 |
| Body | le texte qui a été envoyé | {"commande": 1, "article": "thé"} |
| ReceiptHandle | le ticket pour supprimer cette réception | h-1 |
| ApproximateReceiveCount | combien de fois il a été reçu, en texte | "1" |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Lire une réponse receive
import json
reponse = {
"Messages": [
{"MessageId": "m-1", "ReceiptHandle": "h-1",
"Body": '{"commande": 1, "article": "thé"}',
"Attributes": {"ApproximateReceiveCount": "1"}},
{"MessageId": "m-2", "ReceiptHandle": "h-2", "Body": "deux",
"Attributes": {"ApproximateReceiveCount": "1"}},
]
}
for message in reponse["Messages"]:
print(message["MessageId"], message["Body"])
commande = json.loads(reponse["Messages"][0]["Body"])
print("article :", commande["article"])
# Modifiez la boucle pour afficher aussi le ReceiptHandle.
Un message reçu est caché, pas supprimé
Recevoir ne retire pas le message. La file le cache pendant le délai de visibilité, qui est de 30 secondes sur la file capturée. Les autres travailleurs ne peuvent pas le recevoir tant qu’il est caché.
Quand le travail est fini, appelez delete_message avec le ReceiptHandle. Alors seulement le message disparaît. Si le travailleur plante avant, le délai se termine et le message redevient visible pour un autre.
Exemple travaillé : les attributs d’une file
| Attribut | Valeur | Sens |
|---|---|---|
| VisibilityTimeout | "30" | secondes pendant lesquelles un message reçu reste caché |
| ApproximateNumberOfMessages | "3" | messages qui attendent d’être reçus |
| ApproximateNumberOfMessagesNotVisible | "0" | messages cachés après un receive |
| MessageRetentionPeriod | "345600" | secondes de conservation d’un message, soit quatre jours |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Caché, puis de nouveau visible
DELAI = 30
recu_a = {"m-1": 100}
def est_visible(id_message, maintenant):
if id_message not in recu_a:
return True
return maintenant >= recu_a[id_message] + DELAI
for maintenant in [100, 120, 130, 160]:
print(maintenant, est_visible("m-1", maintenant))
print("m-2 jamais reçu :", est_visible("m-2", 100))
# Mettez DELAI à 60. À quels moments m-1 est-il visible maintenant ?
Erreur fréquente
Attention
Beaucoup croient qu’un receive retire le message. Il le cache seulement. Sans appel à delete_message, le message revient après le délai et est traité de nouveau. Supprimez-le une fois le travail fini, jamais avant.
Au moins une fois : les répétitions existent
La file garde un message jusqu’à sa suppression, donc un message peut arriver deux fois. Un travailleur peut finir son travail et planter avant le delete.
Un receive peut aussi rendre moins de messages que demandé, voire aucun. Une réponse vide n’a pas de clé Messages : testez-la avec in. Écrivez le travailleur pour qu’une répétition ne fasse aucun mal.
Ignorer une répétition
livraisons = ["m-1", "m-2", "m-1", "m-3"]
faits = []
for id_message in livraisons:
if id_message in faits:
print(id_message, "encore : on l'ignore")
else:
faits.append(id_message)
print(id_message, "première fois : on travaille")
vide = {}
if "Messages" in vide:
print("messages :", len(vide["Messages"]))
else:
print("messages : 0")
# Essayez vide["Messages"] directement. Qu'est-ce qui plante ?
Essayez-le dans le lab cloud
Le lab cloud est une copie d'entraînement de S3, SQS et DynamoDB. Appuyez sur Démarrer le lab dans la barre, puis sur Exécuter pour chaque commande ci-dessous. Elles utilisent la vraie ligne de commande AWS, les mêmes mots marchent donc sur un vrai compte. Après la suppression, vous pouvez relancer la commande de réception : elle n'affiche plus rien, car la file est vide. Cette étape sert à s'exercer. Le travail ci-dessous reste du Python simple : vous pouvez le faire sans le lab.
Donnez une clé inventée et l'adresse du lab
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_ENDPOINT_URL=http://cloud:4566Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Créez une file
Q=$(aws sqs create-queue --queue-name orders --query QueueUrl --output text)Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Envoyez un message
aws sqs send-message --queue-url $Q --message-body "order 1"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Recevez-le et gardez la réponse
aws sqs receive-message --queue-url $Q | tee reply.jsonAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Gardez sa poignée de réception
H=$(grep -o '"ReceiptHandle": "[^"]*"' reply.json | cut -d'"' -f4)Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Supprimez le message
aws sqs delete-message --queue-url $Q --receipt-handle "$H"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.