Fehler bewusst behandeln
Manche Fehler lohnen einen zweiten Versuch, andere können nur wieder scheitern. Sie zu unterscheiden trennt eine langsame Minute von einem verbrannten Kontingent.
Was einen erneuten Versuch lohnt
Verzweigen Sie über error.reason, nie über die Meldung: Gründe sind stabil und werden nie umbenannt, Meldungen sind für Menschen geschrieben. Die Fehlerseite listet jeden davon.
| Grund | Status | Wie lange warten |
|---|---|---|
RATE_LIMITED | 429 | Retry-After nennt 60 s. Richten Sie sich nach dem Header, nicht nach der Zahl. |
PAGINATION_BURST | 429 | Exponentielles Backoff mit Jitter. |
DAILY_CAP_EXCEEDED | 429 | Retry-After nennt 3600 s. Richten Sie sich nach dem Header, nicht nach der Zahl. |
DEPENDENCY_UNAVAILABLE | 503 | Exponentielles Backoff mit Jitter. |
MAINTENANCE | 503 | Exponentielles Backoff mit Jitter. |
INTERNAL_ERROR | 500 | Exponentielles Backoff mit Jitter. |
Was durch Wiederholung nicht gelingt
Das sind Antworten, keine Störungen. Sie zu wiederholen kostet Anfragen für denselben Satz, und in einer Schleife erreicht ein Schlüssel so bis mittags sein Tageslimit.
| Grund | Status | Was tatsächlich hilft |
|---|---|---|
KEY_INVALID | 401 | Check the key for a typo, or create a new one in your account. |
KEY_DISABLED | 401 | Re-enable it in your account, or use another key. |
KEY_EXPIRED | 401 | Create a new key in your account. |
PLAN_REQUIRED | 403 | Upgrade the plan. A new key on the same plan will get the same answer. |
ACCOUNT_SUSPENDED | 403 | Contact support. Rotating the key will not help. |
PAGINATION_DEPTH_EXCEEDED | 403 | Narrow the list with filters, or upgrade for deeper paging. |
INVALID_PARAMETER | 400 | Correct the named fields and send the request again. |
RESOURCE_NOT_FOUND | 404 | Check the id. The list and search endpoints return valid ones. |
401 betrifft die Zugangsdaten, 403 das Erlaubte. Ein neuer Schlüssel behebt das Erste und ändert am Zweiten nichts. Authentifizierung zieht die Linie vollständig.
Eine Wiederholungsschleife mit Manieren
Drei Regeln: nur wiederholbare Gründe, das serverseitige Retry-After wo gesendet, und Jitter, damit eine Flotte, die gemeinsam gescheitert ist, nicht gemeinsam wiederholt.
// Retry the failures that can succeed later, and only those.const RETRYABLE = new Set(['RATE_LIMITED', 'PAGINATION_BURST', 'DAILY_CAP_EXCEEDED', 'DEPENDENCY_UNAVAILABLE', 'MAINTENANCE', 'INTERNAL_ERROR']) async function call(request, attempt = 0) { const res = await fetch(request) if (res.ok) return res const body = await res.json().catch(() => null) const reason = body?.error?.reason // A reason the API says is permanent. Sending it again is a // request spent to receive the same sentence. if (!RETRYABLE.has(reason) || attempt >= 4) throw new GunSpecError(res.status, body) // Honour the server's own number when it sends one: it knows when // the window resets and a guess does not. const retryAfter = Number(res.headers.get('Retry-After')) || 0 const backoff = retryAfter * 1000 || 2 ** attempt * 500 // Jitter, or every client that failed together retries together. await sleep(backoff + Math.random() * 250) return call(request, attempt + 1)}Die offiziellen SDKs tun das bereits: maxRetries steht auf 2, Retry-After wird beachtet, und jeder Fehler trägt reason und requestId. Stellen Sie es über retry am Client ein, statt es zu umwickeln. Siehe die SDK-Referenz.
Was die Leser währenddessen sehen
Eine Seite, die ohne unsere Daten rendert, ist besser als eine, die gar nicht rendert. Entscheiden Sie das einmal an der Grenze, nicht in jeder Komponente.
// What the reader sees while this is going wrong.try { return await gunspec.firearms.get(id)} catch (err) { // A copy from ten minutes ago is a better page than an error, and // the catalog changes on the order of days. const stale = await cache.get(id) if (stale) return { ...stale, stale: true } // Nothing cached. Say what failed, quote the request id, and let // the page render the rest of itself. logger.warn({ requestId: err.requestId, reason: err.reason }, 'gunspec unavailable') return null}- Liefern Sie eine veraltete Kopie, bevor Sie einen Fehler liefern. Der Katalog bewegt sich in Tagen, also sind zehn Minuten alte Daten keine Lüge.
- Lassen Sie einen Abschnitt scheitern, nicht die Seite: nicht erreichbare Händler dürfen die Datentabelle nicht mitnehmen.
- Setzen Sie jedem Aufruf ein Timeout. Eine Anfrage, die nie zurückkehrt, ist schlimmer als eine, die scheitert, weil danach nichts mehr entscheiden kann.
- Wiederholen Sie einen Schreibvorgang nie nur wegen einer langsamen Antwort, solange Sie keine Idempotenz haben. Ein Duplikat ist ein echter Schaden, eine Verzögerung nicht.
Wenn es an uns liegt
Jede Antwort trägt X-Request-Id, und jeder SDK-Fehler trägt sie als requestId. Protokollieren Sie sie. Damit finden wir genau diese Anfrage; ohne sie ist eine Meldung die Beschreibung einer Seite. Support und Feedback ist der Weg dorthin.