Die Schlange vor der Bäckerei
Vor einer Bäckerei steht eine Schlange. Wer kommt, stellt sich hinten an. Die Verkäuferin bedient immer die Person ganz vorn.
Eine SQS-Warteschlange macht dasselbe mit Nachrichten. Ein Shop wirft jede neue Bestellung hinein, und ein Worker holt sie nacheinander ab. In dieser Lektion folgen Sie einer Nachricht vom Senden bis zum Löschen.
Am Ende dieser Lektion
Notiz
Ich kann sagen, was mit einer Nachricht vom Senden bis zum Löschen passiert.
Schlüsselwörter
| Begriff | Was er bedeutet |
|---|---|
| Warteschlange | eine Reihe von Nachrichten, die auf ihre Bearbeitung warten |
| Nachricht | ein Stück Text, das in einer Schlange wartet |
| Empfangen | die Schlange um Nachrichten bitten, die Sie bearbeiten wollen |
| Sichtbarkeits-Timeout | wie lange eine empfangene Nachricht unsichtbar bleibt |
| Receipt Handle | die Quittung, mit der Sie eine empfangene Nachricht löschen dürfen |
| At-least-once | eine Nachricht kann mehr als einmal ankommen, kommt aber mindestens einmal an |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Receive gibt Ihnen eine Nachricht
send_message legt Text in die Schlange. Die Antwort enthält eine MessageId. receive_message fordert Nachrichten an. Die Antwort enthält eine Liste namens Messages.
Jede Nachricht hat einen Body, das ist der Text, und ein ReceiptHandle. Ein Body ist nur Text. Viele Shops legen JSON hinein, und der Worker macht daraus mit json.loads wieder ein Dictionary.
Beispiel: eine Receive-Antwort
| Feld | Was darin steht | Beispiel |
|---|---|---|
| Messages | eine Liste mit einem Dictionary pro Nachricht | zwei Nachrichten |
| MessageId | die Id, die die Schlange beim Senden vergab | n-1 |
| Body | der Text, der gesendet wurde | {"bestellung": 1, "artikel": "Brezel"} |
| ReceiptHandle | die Quittung zum Löschen dieses Empfangs | q-1 |
| ApproximateReceiveCount | wie oft sie empfangen wurde, als Text | "1" |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Run: eine Receive-Antwort lesen
import json
antwort = {
"Messages": [
{"MessageId": "n-1", "ReceiptHandle": "q-1",
"Body": "{\"bestellung\": 1, \"artikel\": \"Brezel\"}",
"Attributes": {"ApproximateReceiveCount": "1"}},
{"MessageId": "n-2", "ReceiptHandle": "q-2", "Body": "zwei",
"Attributes": {"ApproximateReceiveCount": "1"}},
]
}
for nachricht in antwort["Messages"]:
print(nachricht["MessageId"], nachricht["Body"])
bestellung = json.loads(antwort["Messages"][0]["Body"])
print("Artikel:", bestellung["artikel"])
# Ändern Sie die Schleife so, dass sie auch das ReceiptHandle ausgibt.
Eine empfangene Nachricht ist versteckt, nicht weg
Ein Receive entfernt keine Nachricht. Er versteckt sie für das Sichtbarkeits-Timeout, bei der aufgezeichneten Schlange 30 Sekunden. Andere Worker können sie in dieser Zeit nicht empfangen.
Ist die Arbeit getan, rufen Sie delete_message mit dem ReceiptHandle auf. Erst dann ist die Nachricht weg. Stürzt der Worker vorher ab, endet das Timeout, und die Nachricht wird für einen anderen Worker wieder sichtbar.
Beispiel: die Attribute einer Schlange
| Attribut | Wert | Bedeutung |
|---|---|---|
| VisibilityTimeout | "30" | Sekunden, die eine empfangene Nachricht versteckt bleibt |
| ApproximateNumberOfMessages | "3" | Nachrichten, die auf den Empfang warten |
| ApproximateNumberOfMessagesNotVisible | "0" | Nachrichten, die nach einem Receive versteckt sind |
| MessageRetentionPeriod | "345600" | Sekunden, die eine Nachricht aufbewahrt wird, also vier Tage |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Run: versteckt, dann wieder sichtbar
FRIST = 30
empfangen_um = {"n-1": 100}
def ist_sichtbar(nachricht_id, jetzt):
if nachricht_id not in empfangen_um:
return True
return jetzt >= empfangen_um[nachricht_id] + FRIST
for jetzt in [100, 120, 130, 160]:
print(jetzt, ist_sichtbar("n-1", jetzt))
print("n-2 nie empfangen:", ist_sichtbar("n-2", 100))
# Ändern Sie FRIST auf 60. Zu welchen Zeiten ist n-1 jetzt sichtbar?
Ein häufiger Fehler
Warnung
Viele denken, ein Receive entferne die Nachricht. Er versteckt sie nur. Rufen Sie delete_message nie auf, kommt die Nachricht nach dem Timeout zurück und wird noch einmal bearbeitet. Löschen Sie sie, wenn die Arbeit getan ist, nie vorher.
At-least-once heißt: Wiederholungen kommen vor
Die Schlange behält eine Nachricht, bis sie gelöscht wird. Darum kann eine Nachricht zweimal ankommen. Ein Worker kann die Arbeit beenden und abstürzen, bevor er löscht.
Ein Receive kann auch weniger Nachrichten liefern, als Sie wollten, oder keine. Eine leere Antwort hat keinen Messages-Eintrag, lesen Sie sie also mit .get. Schreiben Sie den Worker so, dass eine Wiederholung keinen Schaden anrichtet.
Run: eine Wiederholung überspringen
zustellungen = ["n-1", "n-2", "n-1", "n-3"]
erledigt = []
for nachricht_id in zustellungen:
if nachricht_id in erledigt:
print(nachricht_id, "schon gesehen: überspringen")
else:
erledigt.append(nachricht_id)
print(nachricht_id, "zum ersten Mal: Arbeit erledigen")
leer = {}
print("Nachrichten:", len(leer.get("Messages", [])))
# Probieren Sie stattdessen leer["Messages"]. Was geht schief?
Probieren Sie es im Cloud-Lab aus
Das Cloud-Lab ist eine Übungskopie von S3, SQS und DynamoDB. Klicken Sie in der Leiste auf Lab starten und dann bei jedem Befehl unten auf Ausführen. Sie benutzen die echte AWS-Befehlszeile, dieselben Wörter funktionieren also bei einem echten Konto. Fragen Sie die Warteschlange nach dem Löschen noch einmal ab: Sie gibt nichts aus, die Warteschlange wirkt leer. Dieser Schritt dient zum Üben. Die Aufgabe unten bleibt einfaches Python, Sie können sie also ohne das Lab lösen.
Schlüssel und Adresse des Labs setzen
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_ENDPOINT_URL=http://cloud:4566Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine Warteschlange anlegen
Q=$(aws sqs create-queue --queue-name orders --query QueueUrl --output text)Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine Nachricht senden
aws sqs send-message --queue-url $Q --message-body "order 1"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Nachricht empfangen und die Antwort speichern
aws sqs receive-message --queue-url $Q | tee reply.jsonHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Empfangs-Handle behalten
H=$(grep -o '"ReceiptHandle": "[^"]*"' reply.json | cut -d'"' -f4)Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Nachricht löschen
aws sqs delete-message --queue-url $Q --receipt-handle "$H"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.