Manche Fehler beheben sich selbst
Ein Cloud-Dienst beantwortet jeden Aufruf, und manchmal ist die Antwort ein Fehler. Ein Fehlercode sagt Ihnen, welche Art es ist.
Ein fehlender S3-Bucket bleibt fehlend, wenn Sie noch einmal fragen. Eine ausgelastete DynamoDB-Tabelle antwortet vielleicht eine Sekunde später. In dieser Lektion lernen Sie, beides zu unterscheiden und das Richtige zu wiederholen.
Am Ende dieser Lektion
Notiz
Ich kann einen Fehler, den man wiederholt, von einem unterscheiden, den man behebt.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Fehlercode | ein kurzer Name dafür, was schiefging | NoSuchKey |
| Statuscode | eine Zahl, die eine Antwort in eine Familie einordnet | 404 |
| Drosselung | ein Dienst, der Aufrufe ablehnt, weil Sie zu viele geschickt haben | |
| Wiederholung | denselben Aufruf noch einmal schicken | |
| Backoff | vor jeder Wiederholung länger warten | |
| Jitter | ein zufälliger Anteil der Wartezeit, damit Aufrufer nicht im Gleichschritt gehen |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Fehler hat einen Code und einen Status
Schlägt ein Aufruf fehl, gibt Ihnen boto3 einen Fehler. Er enthält einen Statuscode, etwa 404, und einen Fehlercode, etwa NoSuchKey.
Prüfen Sie den Fehlercode und den Status. Prüfen Sie nicht die Meldung: Ihr Wortlaut kann sich zwischen Diensten ändern, und der des Emulators weicht an manchen Stellen vom echten ab.
Beispiel: Fehler, gelesen aus aufgezeichneten Antworten
| Aufruf | Code | Status | Wiederholen? |
|---|---|---|---|
| get_object, Schlüssel fehlt | NoSuchKey | 404 | Nein, den Schlüssel beheben |
| head_object, Schlüssel fehlt | 404 | 404 | Nein, es gibt keinen Body zu lesen |
| list_objects_v2, Bucket fehlt | NoSuchBucket | 404 | Nein, den Bucket anlegen |
| put_item, Bedingung falsch | ConditionalCheckFailedException | 400 | Nein, die Antwort ist die Antwort |
| query, falscher Schlüsselname | ValidationException | 400 | Nein, den Aufruf beheben |
| send_message, Warteschlange fehlt | AWS.SimpleQueueService.NonExistentQueue | 400 | Nein, die Warteschlange anlegen |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Run: Code und Status lesen
antworten = [
{"error": {"Code": "NoSuchKey", "Message": "Fehlt.", "HTTPStatusCode": 404}},
{"error": {"Code": "ConditionalCheckFailedException", "Message": "Nein.", "HTTPStatusCode": 400}},
{"error": {"Code": "InternalServerError", "Message": "Hoppla.", "HTTPStatusCode": 500}},
{"Items": []},
]
for antwort in antworten:
if "error" not in antwort:
print("hat geklappt")
else:
fehler = antwort["error"]
print(fehler["Code"], fehler["HTTPStatusCode"])
Wiederholen Sie, was beim nächsten Mal klappen kann
Manche Fehler sagen: "jetzt nicht". Eine Drosselung heißt, Sie haben zu viele Aufrufe geschickt. Ein Status ab 500 heißt, der Dienst hatte einen Fehler. Beides kann vergehen, wenn Sie warten.
Andere Fehler sagen: "nicht dieser Aufruf". Ihr Aufruf war falsch, also scheitert derselbe Aufruf jedes Mal. Beheben Sie ihn lieber.
Ein häufiger Fehler
Warnung
Viele wiederholen sicherheitshalber jeden Fehler. Ein falscher Schlüssel scheitert dann fünfmal und verschwendet die Wartezeit. Wiederholen Sie nur Drosselungen und Serverfehler. Beheben Sie jeden anderen Fehler, denn derselbe Aufruf bekommt dieselbe Antwort.
Run: Fehler in Wiederholen und Beheben sortieren
# Die Drosselungs-Codes sind die dokumentierten, hier nicht aufgezeichnet.
DROSSELUNG = ["ThrottlingException", "ProvisionedThroughputExceededException", "SlowDown"]
def lohnt_wiederholung(fehler):
if fehler["HTTPStatusCode"] >= 500:
return True
return fehler["Code"] in DROSSELUNG
fehlerliste = [
{"Code": "NoSuchKey", "HTTPStatusCode": 404},
{"Code": "SlowDown", "HTTPStatusCode": 503},
{"Code": "ThrottlingException", "HTTPStatusCode": 400},
{"Code": "ValidationException", "HTTPStatusCode": 400},
]
for fehler in fehlerliste:
print(fehler["Code"], lohnt_wiederholung(fehler))
# Nehmen Sie "RequestLimitExceeded" in DROSSELUNG auf und testen Sie es.
Backoff wartet jedes Mal länger
Ist ein Dienst ausgelastet, macht eine Wiederholung eine Millisekunde später ihn noch voller. Warten Sie also, und nach jedem Fehlschlag länger. Die Wartezeit zu verdoppeln ist üblich. Setzen Sie eine Obergrenze, damit die Wartezeit nie über ein Limit wächst.
Nun kommt Jitter dazu: Warten Sie einen zufälligen Anteil dieser Zeit. Ohne ihn wachen hundert Aufrufer gleichzeitig auf und scheitern gleichzeitig wieder.
Beispiel: die Obergrenze jeder Wartezeit
| Versuch | Verdoppelt | Mit Obergrenze 8 | Wartezeit bei Zufall 0,5 |
|---|---|---|---|
| 1 | 0,5 Sekunden | 0,5 | 0,25 |
| 2 | 1 Sekunde | 1 | 0,5 |
| 3 | 2 Sekunden | 2 | 1 |
| 4 | 4 Sekunden | 4 | 2 |
| 5 | 8 Sekunden | 8 | 4 |
| 6 | 16 Sekunden | 8 | 4 |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Run: eine Wartezeit, die Sie testen können
# zufall ist eine Zahl von 0 bis 1. Ein echter Aufrufer übergibt random.random().
# Ein Test übergibt eine feste Zahl, damit sich die Antwort nie ändert.
def wartezeit(versuch, basis, grenze, zufall):
obergrenze = min(grenze, basis * 2 ** (versuch - 1))
return obergrenze * zufall
for versuch in range(1, 7):
print(versuch, wartezeit(versuch, 0.5, 8, 1.0), wartezeit(versuch, 0.5, 8, 0.5))
# Ändern Sie die Obergrenze von 8 in 2. Welche Versuche ändern sich?