Guide

Ciclo di vita dei batch job

Sync vs async, stati dei job, risultati parziali e webhook

Gli endpoint batch (/batch/distill, /batch/extract) sono asincroni. Un job si muove attraverso una piccola macchina a stati; capire gli stati ti aiuta a decidere tra polling e webhook, e come gestire i fallimenti parziali.

Sync vs async

Sync (/distill, /extract)Async (/batch/distill, /batch/extract)
URL per richiesta1fino a 100
RispostaRisultato completo nel body HTTPJob ID; risultati recuperati separatamente
LatenzaUna richiesta, un'attesaInvio → polling o webhook → fetch
Adatto aUX in tempo reale, tooling per agent, lookup ad-hocJob pianificati, ingestione RAG, monitoraggio
Modalità di fallimentoUn URL sbagliato fa fallire la chiamataUn URL sbagliato fa fallire la sua riga, il job continua
Costo di concorrenzaUno slot per chiamataUno slot per l'intero batch

In caso di dubbio: URL singolo → sync; molti URL o nessuna fretta → async.

Stati del job

StatusSignificato
PENDINGJob accettato, in coda
PROCESSINGAlmeno un URL è in elaborazione
COMPLETEDTutti gli URL hanno raggiunto uno stato terminale (successo o fallimento)
FAILEDErrore fatale a livello di job (raro — di solito fallisce un URL, non l'intero job)
CANCELLEDCancellazione iniziata dall'utente tramite DELETE

Un fallimento di URL non fa fallire il job. Ogni elemento in results[] porta il proprio status: PENDING, PROCESSING, SUCCEEDED o FAILED. Il job passa a COMPLETED quando ogni riga raggiunge uno stato terminale.

Polling vs webhook

Dimensione del jobConsigliatoPerché
< 10 URLPolling ogni 5–10 sL'overhead del webhook non vale il cablaggio
10–100 URLWebhookIl polling brucia ~60 round-trip su un job di 5 minuti
> 100 URL (più batch)WebhookOgni batch si attiva una volta al completamento

Vedi Webhooks per la forma del payload, la verifica della firma (HMAC-SHA256) e il comportamento dei retry.

Risultati parziali

GET /batch/distill/{id} funziona mentre il job è ancora in PROCESSING — ottieni tutto ciò che è terminato finora. Utile per dashboard che fanno streaming delle righe man mano che si completano.

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)

Cancellazione

DELETE /batch/distill/{id} (o /batch/extract/{id}) funziona solo su job PENDING o PROCESSING. Una volta che un job raggiunge uno stato terminale, vi rimane. Gli URL già elaborati in un job cancellato restano fatturabili; gli URL in volo che non avevano finito no.