동기 추론 — run과 subscribe로 한 번에 결과 받기
동기 추론 — run과 subscribe로 한 번에 결과 받기
fal에서 모델을 "그냥 호출해서 결과만 받고 싶을" 때 쓰는 가장 편한 방식이 동기(블로킹) 추론이에요. 요청의 라이프사이클(상태 폴링·재시도 관리)은 신경 쓰지 않고 출력만 필요하다면 이 두 가지 방법 중 하나면 충분해요. run은 큐 없이 fal.run으로 직접 HTTP 요청을 보내 즉시 결과를 돌려주고, subscribe는 내부적으로 큐를 쓰되 폴링을 자동 처리해서 겉으로는 똑같이 단순하면서 자동 재시도·신뢰성을 얹어줘요.
run — 직접 호출
run은 fal.run으로 직접 요청을 보내요. 큐도 상태 폴링도 없이 같은 HTTP 커넥션 안에서 응답을 받아요. SDK가 502/503/504 같은 일시적 HTTP 에러에 대해 재시도는 하지만, 서버 측 큐 재시도는 없어요.
import fal_client
result = fal_client.run(
"fal-ai/flux/schnell",
arguments={"prompt": "a sunset over mountains"},
)
print(result["images"][0]["url"])
빠른 스크립트나 프로토타입, 요청 수명 주기를 직접 다루고 싶지 않은 상황에 어울려요.
subscribe — 큐 기반 신뢰성
subscribe는 큐에 제출한 뒤 결과가 준비될 때까지 알아서 폴링해요. run과 동일한 블로킹 인터페이스로 자동 재시도·타임아웃 처리·스케일링을 함께 받아요. 진행 상황을 보고 싶다면 on_queue_update 콜백으로 로그를 받아볼 수 있어요.
import fal_client
def on_queue_update(update):
if isinstance(update, fal_client.InProgress):
for log in update.logs:
print(log["message"])
result = fal_client.subscribe(
"fal-ai/flux/schnell",
arguments={"prompt": "a sunset over mountains"},
with_logs=True,
on_queue_update=on_queue_update,
)
run() 파라미터
run은 몇 가지 옵션을 받아요. 공통적으로 path, start_timeout, hint, headers를 쓰고, timeout은 처리 시간 상한을 초 단위로 지정해요. start_timeout은 러너가 처리를 시작할 때까지 총 경과 시간을 서버 쪽 데드라인으로 잡고, 넘으면 504를 돌려줘요. hint는 세션 어피니티용 라우팅 힌트로 같은 러너로 요청을 보내게 하고, headers는 재시도 비활성화나 페이로드 저장 같은 플랫폼 제어용 추가 헤더를 실어요.
result = fal_client.run(
"fal-ai/nano-banana-2",
arguments={"prompt": "a sunset"},
path="/custom-endpoint",
timeout=120,
start_timeout=30,
hint="user-session-abc",
headers={"X-Fal-No-Retry": "1"},
)
JavaScript의 fal.run()은 현재 timeout·hint·headers를 지원하지 않아요. 이 옵션들이 필요하면 JavaScript에서는 fal.queue.submit()이나 fal.subscribe()를 쓰는 게 맞아요.
subscribe() 파라미터
subscribe는 위 옵션들에서 timeout을 제외하고 받아요. 여기에 큐 전용 옵션이 더해지는데, 대표적인 것들이 이래요.
client_timeout(Python) /timeout(JS) — 큐 대기와 처리를 포함해subscribe()가 블로킹할 수 있는 클라이언트 쪽 총 데드라인이에요. 초과하면 클라이언트가 폴링을 멈추고 에러를 던져요. Python에서client_timeout만 주고start_timeout을 안 주면 SDK가start_timeout = client_timeout으로 자동 설정해 서버 쪽에서도 같은 데드라인을 지키게 해요.with_logs(Python) /logs(JS) — 상태 업데이트에 러너 로그(모델 코드의 print 출력)를 포함해요. 켜지 않으면 진행 업데이트의logs필드가 비어 있어요.on_enqueue— 요청이 큐에 들어간 직후 한 번 호출되는 콜백이에요.request_id를 받아서 UI에 보여주거나 DB에 저장해 두면 클라이언트가 끊겨도 나중에 결과를 다시 가져올 수 있어요.on_queue_update/onQueueUpdate— 폴링할 때마다 호출되는 콜백이에요. Python에서는 상태 객체가Queued(position 보유)·InProgress(logs 보유)·Completed(logs·metrics 보유) 세 가지 타입으로 주어지고, JavaScript에서는status문자열("IN_QUEUE","IN_PROGRESS","COMPLETED")로 확인해요.
언제 어떤 걸 쓸까요
동기 방식은 요청 라이프사이클을 직접 관리할 필요 없이 결과만 원하는 간단한 스크립트·프로토타입에 적합해요. 오버헤드 없이 가장 빠른 경로가 필요하면 run, 큐 기반 자동 재시도로 안정성을 챙기려면 subscribe를 고르면 돼요. 병렬 처리나 웹훅이 필요한 프로덕션 워크로드는 비동기(큐) 추론이 더 알맞아요.
인프라 문제(타임아웃·러너 에러)로 요청이 실패하면 응답 JSON에 detail과 error_type 필드가 들어오고 X-Fal-Error-Type 헤더도 함께 붙어요. 모델 입력 검증 에러(잘못된 입력·콘텐츠 정책 위반)는 별도의 모델 에러 규칙을 따르니 구분해서 보면 돼요.