가이드
배치 작업 라이프사이클
동기 vs 비동기, 작업 상태, 부분 결과, 그리고 Webhook
배치 엔드포인트(/batch/distill, /batch/extract)는 비동기입니다. 작업은 작은 상태 머신을 따라 이동합니다; 상태를 이해하면 폴링과 Webhook 중 무엇을 선택할지, 부분 실패를 어떻게 다룰지 결정하는 데 도움이 됩니다.
동기 vs 비동기
동기 (/distill, /extract) | 비동기 (/batch/distill, /batch/extract) | |
|---|---|---|
| 요청당 URL | 1 | 최대 100 |
| 응답 | HTTP 본문에 전체 결과 | Job ID; 결과는 별도 조회 |
| 지연 시간 | 한 번 요청, 한 번 대기 | 제출 → 폴링 또는 Webhook → 가져오기 |
| 적합한 곳 | 실시간 UX, 에이전트 도구, 임시 조회 | 스케줄 작업, RAG ingestion, 모니터링 |
| 실패 모드 | 잘못된 URL 하나가 호출 전체를 실패시킴 | 잘못된 URL 하나가 그 행만 실패, 작업은 계속 |
| 동시성 비용 | 호출당 한 슬롯 | 배치 전체에 한 슬롯 |
판단이 안 설 때: 단일 URL → 동기; 여러 URL이거나 급하지 않으면 → 비동기.
작업 상태
| Status | 의미 |
|---|---|
PENDING | 작업 수락, 큐에 대기 |
PROCESSING | 적어도 하나의 URL이 처리 중 |
COMPLETED | 모든 URL이 종료 상태(성공 또는 실패) 도달 |
FAILED | 작업 수준의 치명적 오류(드묾 —— 보통 URL 하나만 실패하지 작업 전체가 실패하지는 않음) |
CANCELLED | DELETE를 통한 사용자 주도 취소 |
URL 실패는 작업을 실패시키지 않습니다. results[]의 각 항목이 자체 status를 갖습니다: PENDING, PROCESSING, SUCCEEDED, 또는 FAILED. 모든 행이 종료 상태에 도달하면 작업이 COMPLETED로 이동합니다.
폴링 vs Webhook
| 작업 크기 | 권장 | 이유 |
|---|---|---|
| < 10 URL | 5–10초마다 폴링 | Webhook 오버헤드가 배선 비용 대비 가치 없음 |
| 10–100 URL | Webhook | 5분짜리 작업에서 폴링이 약 60회 왕복을 소모 |
| > 100 URL(여러 배치) | Webhook | 각 배치가 완료 시 한 번씩 발사 |
페이로드 형태, 서명 검증(HMAC-SHA256), 재시도 동작은 Webhook을 참고하세요.
부분 결과
GET /batch/distill/{id}는 작업이 아직 PROCESSING인 동안에도 동작합니다 —— 그때까지 끝난 만큼 받게 됩니다. 행이 완료되는 대로 스트리밍하는 대시보드에 유용합니다.
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)취소
DELETE /batch/distill/{id}(또는 /batch/extract/{id})는 PENDING 또는 PROCESSING 작업에서만 동작합니다. 작업이 종료 상태에 진입하면 그대로 머무릅니다. 취소된 작업에서 이미 처리된 URL은 여전히 과금 대상이며, 아직 끝나지 않은 in-flight URL은 과금되지 않습니다.