Ciclo de Vida do Job em Batch
Sync vs async, estados do job, resultados parciais e webhooks
Os endpoints de batch (/batch/distill, /batch/extract) são assíncronos. Um job percorre uma pequena máquina de estados; entender os estados ajuda você a escolher entre polling e webhooks, e como tratar falhas parciais.
Sync vs async
Sync (/distill, /extract) | Async (/batch/distill, /batch/extract) | |
|---|---|---|
| URLs por requisição | 1 | até 100 |
| Resposta | Resultado completo no corpo HTTP | Job ID; resultados buscados separadamente |
| Latência | Uma requisição, uma espera | Submeter → polling ou webhook → buscar |
| Melhor para | UX em tempo real, ferramentas para agentes, consultas pontuais | Jobs agendados, ingestão RAG, monitoramento |
| Modo de falha | Uma URL ruim falha a chamada inteira | Uma URL ruim falha a sua linha, o job continua |
| Custo de concorrência | Um slot por chamada | Um slot para o batch inteiro |
Em caso de dúvida: uma URL → sync; muitas URLs ou sem pressa → async.
Estados do job
| Status | Significado |
|---|---|
PENDING | Job aceito, na fila |
PROCESSING | Pelo menos uma URL está sendo processada |
COMPLETED | Todas as URLs atingiram um estado terminal (sucesso ou falha) |
FAILED | Erro fatal em nível de job (raro — geralmente uma URL falha, não o job inteiro) |
CANCELLED | Cancelamento iniciado pelo usuário via DELETE |
Uma falha de URL não falha o job. Cada item em results[] carrega seu próprio status: PENDING, PROCESSING, SUCCEEDED ou FAILED. O job vai para COMPLETED assim que toda linha atinge um estado terminal.
Polling vs webhooks
| Tamanho do job | Recomendado | Por quê |
|---|---|---|
| < 10 URLs | Polling a cada 5–10 s | O overhead de webhook não compensa o setup |
| 10–100 URLs | Webhook | Polling queima ~60 round-trips em um job de 5 minutos |
| > 100 URLs (vários batches) | Webhook | Cada batch dispara uma vez na conclusão |
Veja Webhooks para formato do payload, verificação de assinatura (HMAC-SHA256) e comportamento de retry.
Resultados parciais
GET /batch/distill/{id} funciona enquanto o job ainda está PROCESSING — você obtém o que já terminou. Útil para dashboards que streamam linhas conforme completam.
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)Cancelamento
DELETE /batch/distill/{id} (ou /batch/extract/{id}) só funciona em jobs PENDING ou PROCESSING. Uma vez que o job atinge um estado terminal, ele permanece lá. URLs já processadas em um job cancelado continuam sendo cobradas; URLs em andamento que ainda não terminaram, não.