uncloth.app Guides

Bildgenerierung skalieren: Queues, Idempotenz und Retries

Bildgenerierung bricht die Annahmen, auf denen die meisten Web-Architekturen aufbauen. Anfragen dauern Dutzende Sekunden statt Millisekunden, die Kapazität ist wirklich endlich, weil sie physisch ist, und eine fehlgeschlagene Anfrage hat bereits echtes Geld gekostet. Die Muster, die das korrekt halten, sind gut bekannt — sie sind nur nicht die, die ein typisches CRUD-Backend schon mitbringt.

Die Queue ist das Design

Der erste Reflex ist, die API direkt aus dem Request-Handler aufzurufen. In der Entwicklung funktioniert das und scheitert beim ersten echten Traffic, weil nichts zwischen Nachfrage und Kapazität steht: Eine Spitze wird zur Wand aus Timeouts, und es gibt keine Aufzeichnung darüber, was beim Neustart des Prozesses noch lief.

Setzen Sie eine dauerhafte Queue dazwischen. „Dauerhaft“ ist das entscheidende Wort — eine Liste im Arbeitsspeicher verliert bei jedem Deploy alle laufenden Jobs, und Deploys passieren mitten im Traffic. Eine Datenbanktabelle reicht in dieser Größenordnung völlig aus und liefert als Nebeneffekt einen wiederherstellbaren Zustandsverlauf.

Backpressure ist ein Feature

Mit einer Queue können Sie entscheiden, wie viele Jobs gleichzeitig in Bearbeitung sein dürfen — und dieses Limit ist eine Produktentscheidung, kein technisches Detail. Zu hoch, und alles ist für alle langsam. Zu niedrig, und Kapazität liegt brach, während sich eine Queue aufbaut. Entscheidend ist, dass das Limit existiert und an genau einer Stelle durchgesetzt wird, damit eine Traffic-Spitze die Warteschlange verlängert, statt jede einzelne Anfrage zu verschlechtern.

Idempotenz und der mehrdeutige Fehler

Der Fehlerfall, der Geld kostet, ist keine Fehlerantwort — Fehler sind einfach. Es ist der mehrdeutige Fall: Der Request hat Ihren Prozess verlassen, die Verbindung brach ab, und Sie können nicht sagen, ob der Job angelegt wurde. Wiederholen Sie ihn, haben Sie womöglich doppelt bezahlt. Wiederholen Sie ihn nicht, hat ein Nutzer womöglich für nichts bezahlt.

Ein Idempotency Key löst das, indem er den Retry sicher macht: Derselbe Key liefert den ursprünglichen Job zurück, statt einen zweiten zu erzeugen. Die Regeln sind einfach und leicht falsch zu machen — erzeugen Sie den Key, wenn der Nutzer handelt, nicht wenn der HTTP-Call abgesetzt wird; speichern Sie ihn zum Job-Datensatz; verwenden Sie ihn bei jedem Retry dieser Aktion wieder.

# derselbe Key für jeden Retry einer Nutzeraktion
KEY=$(uuidgen)
curl -X POST https://api.example/api/v1/jobs \
  -H "X-API-Key: $API_KEY" -H "Idempotency-Key: $KEY" \
  -F image=@photo.jpg -F feature=undress -F consent=confirmed

Was Sie nicht automatisch wiederholen sollten

Es gibt eine Fehlerklasse, bei der Anhalten der sichere Zug ist. Ist Ihr Prozess zwischen dem Absenden einer Übermittlung und dem Festhalten der Antwort gestorben, wissen Sie tatsächlich nicht, was passiert ist — und ohne Key zum Deduplizieren ist ein automatischer Retry ein Münzwurf, der doppelt abrechnen kann. Markieren Sie solche Jobs als prüfungsbedürftig, statt sie blind zu wiederholen. Ein sichtbar hängender Job ist ein besseres Ergebnis als eine stille Doppelbelastung.

Abgleich: die Schleife, die Sie rettet

Live-Events sind bequem und unzuverlässig. Sockets brechen weg, Prozesse starten neu, und genau die Nachricht, auf die es ankam, trifft ein, während niemand zuhört. Die Lösung ist eine Hintergrundschleife, die die API regelmäßig nach jedem Job fragt, den Ihre Datenbank noch als aktiv führt, und den Zustand aus der Antwort aktualisiert.

Diese eine Schleife absorbiert eine ganze Klasse von Fehlern. Verpasste Events spielen keine Rolle mehr. Ein Neustart mitten in der Generierung spielt keine Rolle mehr. Jeder Job konvergiert innerhalb eines Abgleichintervalls zu seinem wahren Zustand — was auch immer der Verbindung dazwischen zugestoßen ist.

Fortschritt ohne Ihre Datenbank zu erschlagen

Die Generierung meldet Fortschritt häufig — potenziell mehrmals pro Sekunde und Job. Jeden Tick in die Datenbank zu schreiben vervielfacht Ihre Schreiblast ohne zusätzlichen Informationsgewinn. Drosseln Sie die Persistenz auf etwa einmal pro Sekunde und schreiben Sie immer den Endzustand; die Live-Werte senden Sie an verbundene Clients, ohne den Speicher überhaupt anzufassen.

Eine Checkliste, die trägt

  • Dauerhafte Queue zwischen Nutzern und API, nach einem Neustart wiederherstellbar.
  • Ein explizites Limit gleichzeitiger Jobs, an einer Stelle durchgesetzt.
  • Idempotency Key pro Nutzeraktion erzeugt, gespeichert und beim Retry wiederverwendet.
  • Mehrdeutige Übermittlungsfehler markiert statt automatisch wiederholt.
  • Eine Abgleichschleife, die den Zustand unabhängig von verpassten Events konvergieren lässt.
  • Gedrosselte Fortschritts-Schreibvorgänge, Live-Fortschritt über den Socket.

Nichts davon ist spezifisch für Bildgenerierung — es ist gewöhnliche Hygiene verteilter Systeme. Sie wird hier nur sichtbar, weil jede Arbeitseinheit langsam und teuer genug ist, dass die üblichen Abkürzungen aufhören, unsichtbar zu sein.

Häufige Fragen

Brauche ich einen Message Broker?

In dieser Größenordnung meist nicht. Eine Datenbanktabelle mit einer Claim-Query gibt Ihnen Dauerhaftigkeit und einen wiederherstellbaren Zustandsverlauf, ohne ein weiteres bewegliches Teil.

Wie viele Jobs sollte ich gleichzeitig zulassen?

Starten Sie niedrig, messen Sie Wartezeit in der Queue gegen Bearbeitungszeit und erhöhen Sie, bis sich die Latenz nicht mehr verbessert. Die Zahl zählt weniger als ein einziges durchgesetztes Limit.

Sollten fehlgeschlagene Jobs automatisch wiederholt werden?

Bei klaren Fehlern ja. Bei mehrdeutigen Übermittlungsfehlern, wo Sie nicht wissen, ob Arbeit angelegt wurde, nein — markieren Sie sie, denn ein blinder Retry kann eine bezahlte Generierung verdoppeln.

Mit uncloth.app entwickeln

Ein REST-Endpunkt, elf Presets, Ergebnisse direkt an Ihr Backend. Schreiben Sie uns, was Sie bauen, und wir schicken Ihnen die Zugangsdaten.

Zugang anfragen

Alle Guides