Einführung
Wiederholte Aufträge für dieselbe Bestellung müssen das abgeschlossene Geschäftsergebnis erhalten. Du ergänzt einen bereitgestellten Verbraucher um einen atomaren Schreibschutz, testest wiederholte und unabhängige Bestellungen und bestätigst die erfolgreiche Nachrichtenbestätigung.
Schließe zuerst Fehlgeschlagene Aufträge mit einer Dead-Letter-Queue isolieren, Doppelte Bestellungen mit bedingten Schreibvorgängen verhindern und Eine Lambda-Funktion konfigurieren und diagnostizieren ab. Diese unabhängige VM stellt den anfänglichen Worker, die Rolle und eine leere Bestelltabelle bereit.
Bezug zu Zertifizierungen
Dieses Lab bietet praktische Übungen zu den folgenden Prüfungsthemen.
- Solutions Architect – Associate (SAA-C03) · Aufgabe 2.1: Idempotente Consumer und Schutz der Geschäftsergebnisse.
- Developer – Associate (DVA-C02) · Aufgabe 1.1: Idempotente Consumer und Schutz der Geschäftsergebnisse.
- DevOps Engineer – Professional (DOP-C02) · Aufgabe 5.1: Grundlagenübung: Idempotente Consumer und Schutz der Geschäftsergebnisse.
- Solutions Architect – Professional (SAP-C02) · Aufgabe 2.4: Grundlagenübung: Idempotente Consumer und Schutz der Geschäftsergebnisse.
Eine leere Warteschlange mit dem Worker verbinden
Erstelle in diesem Schritt eine Warteschlange und verbinde den bereitgestellten Verbraucher, bevor du geschäftliche Aufträge sendest.
Verwende AWS View neben Terminal, um aktuelle Warteschlangen, Worker-Ergebnisse und gespeicherte Bestellungen zu vergleichen. Erhalte die unbeteiligten Referenzdaten.
cd /home/labex/project
Erstelle die Standardwarteschlange. Die Befehlsersetzung $(...) speichert die zurückgegebene Warteschlangen-URL für spätere Operationen:
QUEUE_URL=$(aws sqs create-queue --queue-name labex-q05-jobs --attributes VisibilityTimeout=30 --query QueueUrl --output text)
Wähle ihre ARN aus und erstelle eine Ereignisquellenzuordnung mit Batchgröße eins:
QUEUE_ARN=$(aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names QueueArn --query Attributes.QueueArn --output text)
MAPPING_ID=$(aws lambda create-event-source-mapping --function-name labex-q05-worker --event-source-arn "$QUEUE_ARN" --batch-size 1 --enabled --query UUID --output text)
Untersuche die Verbindung:
aws lambda get-event-source-mapping --uuid "$MAPPING_ID" --query '{Source:EventSourceArn,Function:FunctionArn,Batch:BatchSize,State:State}'
Erwarte die Quelle labex-q05-jobs, labex-q05-worker, die Batchgröße 1 und den Zustand Enabled. Die bereitgestellte Rolle kann nur diese Warteschlange abfragen und deren Nachrichten löschen sowie nur in die Bestelltabelle und Ausführungslogs schreiben. AWS View zeigt eine leere Warteschlange, keine Bestellung und keine Schreibentscheidungen. Sende keinen Auftrag, bevor du im nächsten Schritt den Schutz bereitgestellt hast.
Einen atomaren Schutz anhand des Geschäftsschlüssels bereitstellen
Ersetze in diesem Schritt den bedingungslosen Schreibvorgang des Workers und belege, dass der erste geschützte Auftrag erfolgreich ist.

Unterschiedliche Warteschlangennachrichten können dieselbe geschäftliche ID enthalten. Der Worker bestätigt ein übereinstimmendes Duplikat, ohne die Bestellung erneut zu schreiben.
Ein idempotenter Verbraucher erhält dasselbe Geschäftsergebnis, wenn wiederholte Arbeit eintrifft. DynamoDB wertet ConditionExpression='attribute_not_exists(id)' in derselben Schreiboperation wie PutItem aus. Dies vermeidet ein Rennen zwischen separatem Lesen und anschließendem Schreiben. Die geschäftliche id ist der Schlüssel; die Verwendung von SQS-messageId würde einer neu gesendeten Kopie derselben Bestellung erlauben, erneut zu schreiben.
Bei einer fehlgeschlagenen Bedingung gibt ReturnValuesOnConditionCheckFailure='ALL_OLD' das vorhandene Element zurück. Der Code fängt nur ConditionalCheckFailedException ab und vergleicht dieses Element mit dem angeforderten Element. Identische Details sind ein abgeschlossenes Duplikat; widersprüchliche Details oder ein anderer Fehler schlagen weiterhin fehl, statt stillschweigend bestätigt zu werden.
Schreibe den vollständigen Worker unten. cat > app.py ersetzt die Datei, und das Here-Dokument liefert ihren Inhalt bis zur Abschlussmarkierung PY. Die Anführungszeichen in 'PY' verhindern die Shellersetzung innerhalb des Python-Codes:
cat > app.py <<'PY'
import json
import os
import boto3
from botocore.exceptions import ClientError
def handler(event, context):
print('EVENT '+json.dumps(event,sort_keys=True))
if set(event)!={'Records'} or len(event['Records'])!=1:
raise ValueError('Expected one SQS record')
job=json.loads(event['Records'][0]['body'])
print('JOB '+json.dumps(job,sort_keys=True))
if set(job)!={'id','quantity'} or not isinstance(job['id'],str):
raise ValueError('Use an id and quantity')
quantity=job['quantity']
if isinstance(quantity,bool) or not isinstance(quantity,int) or not 1<=quantity<=10:
raise ValueError('Quantity must be an integer from 1 to 10')
database=boto3.client('dynamodb',endpoint_url='http://127.0.0.1:5000',region_name='us-east-1')
item={'id':{'S':job['id']},'quantity':{'N':str(quantity)},'total_cents':{'N':str(quantity*250+100)}}
try:
database.put_item(TableName=os.environ['TABLE_NAME'],Item=item,
ConditionExpression='attribute_not_exists(id)',
ReturnValuesOnConditionCheckFailure='ALL_OLD')
result={'id':job['id'],'quantity':quantity,'processed':True,'duplicate':False}
except ClientError as error:
if error.response['Error']['Code']!='ConditionalCheckFailedException':
raise
if error.response.get('Item')!=item:
raise ValueError('Order ID already exists with different details') from error
result={'id':job['id'],'quantity':quantity,'processed':False,'duplicate':True}
print('RESULT '+json.dumps(result,sort_keys=True))
return result
PY
Das Einlesen des Ereignisses und die Mengenprüfungen sind bereitgestellter Kontext. Die wesentliche Änderung ist das einzelne bedingte put_item, dessen eng begrenzte Fehlerbehandlung und das Ergebnis processed/duplicate. Ein Duplikat kehrt erfolgreich zurück, damit der Verbraucher seine SQS-Kopie bestätigen kann, nachdem das Geschäftsergebnis bereits erhalten wurde.
Verpacke app.py im Stammverzeichnis des ZIP-Archivs. Der Handler der vorhandenen Funktion ist app.handler, daher ist der Moduldateiname entscheidend:
zip -q function.zip app.py
Lade das binäre ZIP mit fileb:// hoch:
aws lambda update-function-code --function-name labex-q05-worker --zip-file fileb://function.zip --query CodeSha256 --output text
Der zurückgegebene Hash bezeichnet den bereitgestellten Code; tatsächliche Verarbeitung wird sein Verhalten belegen. Sende die erste Bestellung:
aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"dedup-order","quantity":4}'
Beobachte AWS View, bis die Warteschlange leer ist, der Worker processed: true meldet und die Bestellung erscheint. Lies sie dann aus:
aws dynamodb get-item --table-name labex-q05-orders --key '{"id":{"S":"dedup-order"}}' --consistent-read --query Item
Erwarte die Menge 4 und den Gesamtbetrag 1100. Die Schreibentscheidung zeigt die Bedingung, Accepted, kein vorheriges Element und anschließend dieses gespeicherte Element. Eine konfigurierte Bedingung oder eine hochgeladene Datei allein kann erfolgreiche Arbeit nicht belegen.
Wiederholte Aufträge ohne erneuten Schreibvorgang verarbeiten
Sende in diesem Schritt zwei neue Kopien derselben geschäftlichen Bestellung und belege, dass eine andere Bestellung weiterhin unabhängig abgeschlossen wird.
Sende dieselbe geschäftliche Nutzlast zweimal. Jede SendMessage-Antwort hat eine neue SQS-Nachrichten-ID, aber der Bestellschlüssel bleibt dedup-order:
aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"dedup-order","quantity":4}'
aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"dedup-order","quantity":4}'
Sende einen unabhängigen Geschäftsschlüssel:
aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"other-order","quantity":1}'
Beobachte AWS View, bis vier tatsächliche Ausführungen zurückgekehrt sind und die Warteschlange leer ist. Die beiden Wiederholungsausführungen melden processed: false, duplicate: true. DynamoDB weist beide bedingten Schreibvorgänge mit ConditionalCheckFailedException zurück; jedes Element bleibt vor und nach dem Versuch unverändert. Die erste Bestellung und other-order haben jeweils einen akzeptierten Schreibvorgang. Der Verbraucher bestätigt die wiederholten Kopien, statt bereits abgeschlossene Arbeit erneut zu versuchen.
Lies die Geschäftsergebnisse aus:
aws dynamodb scan --table-name labex-q05-orders --query Items
Erwarte genau dedup-order/4/1100 und other-order/1/350; die Elementreihenfolge kann abweichen. Untersuche die tatsächlichen Worker-Ergebnisse. Ein Log-Ereignis kann mehrere Zeilen enthalten; diese Pipeline sendet die JSON-Ausgabe des Dienstes an jq -r, teilt jedes Ereignis in Zeilen auf und wählt nur RESULT-Zeilen aus, sodass Empfangskennungen aus den angezeigten Ergebnissen herausbleiben:
aws logs filter-log-events --log-group-name /aws/lambda/labex-q05-worker --filter-pattern '"RESULT"' --output json | jq -r '.events[].message | split("\n")[] | select(startswith("RESULT "))'
Prüfe die Bestätigung:
aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible
Beide Zähler sind null. Es gab vier tatsächliche Nachrichtenzustellungen und Funktionsausführungen, zwei akzeptierte geschäftliche Schreibvorgänge und zwei bedingte Zurückweisungen durch den Dienst. Das bloße Zählen der Tabellenelemente würde bedingungslose Überschreibungen nicht aufdecken; verwende zusätzlich die tatsächlichen Entscheidungen und die zugehörigen Verbraucherergebnisse.
Der Schutz sichert ein Geschäftselement. Er macht den DynamoDB-Schreibvorgang und die SQS-Bestätigung nicht zu einer einzigen atomaren Operation. Der Bestelldatensatz ist der dauerhafte Duplikatschutz. Seine Entfernung erlaubt demselben Schlüssel, erneut ein Element zu erstellen. Aufbewahrung und Gestaltung des Geschäftsschlüssels sind daher Teil der Richtlinien eines tatsächlichen Systems. Diese fiktiven Wiederholungen zeigen sichere Arbeit für dasselbe Geschäftsobjekt; sie belegen weder eine Nebenläufigkeitsgarantie in der Produktion noch eine durchgängige Genau-einmal-Garantie.

Verbraucherverbindung und Geschäftsergebnisse entfernen
Entferne in diesem Schritt die eigene Verbindung und die eigenen Ressourcen, nachdem du die Duplikatbehandlung bestätigt hast.
Stoppe deine Ereignisquellenzuordnung, bevor du ihre Quellwarteschlange löschst:
aws lambda delete-event-source-mapping --uuid "$MAPPING_ID" --query UUID --output text
aws sqs delete-queue --queue-url "$QUEUE_URL"
Entferne beide fiktiven Geschäftselemente und die Ausführungslogs dieses Labs:
aws dynamodb delete-item --table-name labex-q05-orders --key '{"id":{"S":"dedup-order"}}'
aws dynamodb delete-item --table-name labex-q05-orders --key '{"id":{"S":"other-order"}}'
aws logs delete-log-group --log-group-name /aws/lambda/labex-q05-worker
Bestätige das Fehlen eigener Ressourcen und erhalte unbeteiligte Referenzdaten:
aws lambda list-event-source-mappings --function-name labex-q05-worker --query EventSourceMappings
aws sqs list-queues
aws dynamodb scan --table-name labex-q05-orders --query Items
aws dynamodb scan --table-name labex-q05-reference --query Items
Zuordnungen und Bestellungen sind leer, es bleiben keine Warteschlangen-URLs übrig, und das Referenzelement enthält weiterhin keep unchanged. Bereitgestellte Funktion und Tabellenstrukturen bleiben für die Umgebung erhalten. Ein Netzwerk- oder Authentifizierungsfehler kann eine Löschung nicht belegen. AWS View behält historische Schreibentscheidungen bei und zeigt gleichzeitig die leeren aktuellen Ressourcen.
Entferne deine gewöhnlichen Code- und Archivdateien:
rm -f app.py function.zip
Führe die Bereinigungsprüfung aus, bevor du die Umgebung beendest.
Zusammenfassung
Du hast eine atomare DynamoDB-Bedingung anhand des Geschäftsschlüssels in einem tatsächlichen Warteschlangenverbraucher bereitgestellt. Die erste Bestellung wurde abgeschlossen; zwei separat gesendete Kopien wurden verarbeitet und bestätigt, nachdem die bedingte Zurückweisung durch den Dienst das ursprüngliche Element erhalten hatte. Ein anderer Schlüssel erzeugte weiterhin sein eigenes Ergebnis. Tatsächliche Schreibvorgänge, Worker-Ergebnisse und der leere Warteschlangenzustand belegten das Ergebnis vor der gezielten Bereinigung.
Die Challenge wendet begrenzte Fehlerisolierung an, und das Serverless-Projekt kombiniert anschließend die DLQ-Wiederherstellung mit diesem Schutz anhand des Geschäftsschlüssels.



