Lebenszyklus von Batch-Jobs
Sync vs. async, Job-Zustände, Teilergebnisse und Webhooks
Batch-Endpunkte (/batch/distill, /batch/extract) sind asynchron. Ein Job durchläuft eine kleine Zustandsmaschine; die Zustände zu verstehen hilft dir bei der Wahl zwischen Polling und Webhooks und beim Umgang mit Teilfehlern.
Sync vs. async
Sync (/distill, /extract) | Async (/batch/distill, /batch/extract) | |
|---|---|---|
| URLs pro Anfrage | 1 | bis zu 100 |
| Antwort | Vollständiges Ergebnis im HTTP-Body | Job-ID; Ergebnisse separat abrufen |
| Latenz | Eine Anfrage, ein Warten | Einreichen → Polling oder Webhook → Abruf |
| Am besten für | Echtzeit-UX, Agent-Tools, Ad-hoc-Lookups | Geplante Jobs, RAG-Ingestion, Monitoring |
| Fehlermodus | Eine schlechte URL bringt den Aufruf zum Scheitern | Eine schlechte URL bringt ihre Zeile zum Scheitern, der Job läuft weiter |
| Kosten für Concurrency | Ein Slot pro Aufruf | Ein Slot für den ganzen Batch |
Im Zweifelsfall: einzelne URL → sync; viele URLs oder ohne Eile → async.
Job-Zustände
| Status | Bedeutung |
|---|---|
PENDING | Job angenommen, in der Warteschlange |
PROCESSING | Mindestens eine URL wird verarbeitet |
COMPLETED | Alle URLs haben einen terminalen Zustand erreicht (Erfolg oder Fehler) |
FAILED | Fataler Job-Level-Fehler (selten — meist scheitert eine URL, nicht der ganze Job) |
CANCELLED | Vom Nutzer per DELETE initiierte Stornierung |
Ein URL-Fehler bringt den Job nicht zum Scheitern. Jedes Element in results[] trägt seinen eigenen status: PENDING, PROCESSING, SUCCEEDED oder FAILED. Der Job wechselt zu COMPLETED, sobald jede Zeile einen terminalen Zustand erreicht hat.
Polling vs. Webhooks
| Job-Größe | Empfohlen | Warum |
|---|---|---|
| < 10 URLs | Alle 5–10 s pollen | Webhook-Overhead lohnt die Verkabelung nicht |
| 10–100 URLs | Webhook | Polling verbrennt ~60 Round-Trips bei einem 5-Minuten-Job |
| > 100 URLs (mehrere Batches) | Webhook | Jeder Batch feuert einmal beim Abschluss |
Siehe Webhooks für Payload-Form, Signatur-Verifikation (HMAC-SHA256) und Wiederholungsverhalten.
Teilergebnisse
GET /batch/distill/{id} funktioniert, während der Job noch PROCESSING ist — du bekommst, was bisher fertig ist. Nützlich für Dashboards, die Zeilen streamen, sobald sie fertig sind.
import httpx, time
API = "https://openapi.thunderbit.com/openapi/v1"
H = {"Authorization": "Bearer YOUR_API_KEY"}
job = httpx.post(f"{API}/batch/distill", headers=H,
json={"urls": urls}).json()
batch_id = job["data"]["id"]
while True:
body = httpx.get(f"{API}/batch/distill/{batch_id}", headers=H).json()["data"]
fresh = [r for r in body["results"] if r["status"] == "SUCCEEDED"]
yield_to_dashboard(fresh)
if body["status"] in ("COMPLETED", "FAILED", "CANCELLED"):
break
time.sleep(5)Stornierung
DELETE /batch/distill/{id} (oder /batch/extract/{id}) funktioniert nur bei PENDING- oder PROCESSING-Jobs. Sobald ein Job einen terminalen Zustand erreicht, bleibt er dort. Bereits verarbeitete URLs in einem stornierten Job bleiben abrechenbar; in-flight URLs, die nicht fertig waren, nicht.