아이피아 · 미니게이트
Poptale Image Engine
아이피아 2026. 07 – 현재
미니게이트 2026. 06 – 2026. 07
Overview
Poptale과 AI Character Chat이 함께 사용하는 ComfyUI 워크플로 레지스트리이자 GPU 작업 물류 엔진입니다. BFF 내부에 있던 분산 실행 로직을 분리한 뒤, 호출자가 ComfyUI graph를 직접 조립하지 않도록 실행 계약과 자산 카탈로그까지 엔진이 소유하도록 확장했습니다.
호출자는 workflowId + inputs와 추적용 메타데이터만 전달합니다. 엔진은 입력 검증, graph 렌더링,
우선순위 큐 적재, 워커 라우팅, 실행 추적, 결과 회수와 콜백 재시도를 담당하고 작품·회차·결제 같은 제품 도메인에는 관여하지 않습니다.
My Role
- BFF에서 GPU 오케스트레이션을 분리하고 도메인 독립 API·상태 모델 설계
- Workflow Registry, Style/Character LoRA Catalog와 Workflow Studio 구현
- Redis 기반 다단 우선순위 큐, 그룹 스티키·최소 부하 라우팅과 풀 격리 구현
- 재시도 가능한 콜백, 상태 조회 안전망, 워커 드레인·동적 합류 구조 설계
- pytest 배포 게이트와 Artifact Registry·GCE CI/CD 구축
Architecture
Registry → Dispatcher → Router → Priority Queue → Consumer → ComfyUI → Poller/Inbound Callback → Callback Emitter로 이어지는 비동기 파이프라인을 FastAPI와 Redis(async)로 구현했습니다.
- Workflow Registry — 입력 스키마·기본값·node binding·출력 규약·버전·실행 풀의 단일 출처
- LoRA Catalog — Style/Character/Outfit ID를 모델 경로·강도·trigger words로 안전하게 해석
- Dispatcher & Router — ULID·랜덤 seed 생성, graph 렌더링, 우선순위와 부하·그룹 친화도를 반영한 워커 선택
- Consumer & Poller — Pacer를 거쳐 ComfyUI에 제출하고 /history 또는 GPU 콜백으로 상태·출력을 회수
- Callback Emitter — 표준 상태와 node별 URL, 호출자 meta를 전달하고 실패 시 Redis ZSET에서 재시도
주요 구현
계약 기반 Workflow Registry & Studio
ComfyUI graph를 호출자 코드에서 제거하고, 버전이 붙은 약 20개 워크플로의 호출·실행 계약을 엔진 catalog로 통합했습니다.
- Pydantic 모델과 catalog schema로 필수값·타입·enum·길이·LoRA 호환성을 큐 적재 전에 검증
- Krea2·MiniMax처럼 참조 이미지 수에 따라 달라지는 graph도
ref_urls만 받아 빈 노드를 엔진에서 prune - Workflow Studio에서 API-format JSON 분석 → 커스텀 입력 지정 → 버전 게시 → 검증·실행까지 지원
- 게시 버전과 SHA-256, 호출처, 출력 node 계약을 보존하고 raw prompt graph는 외부에 노출하지 않음
GPU 캐시·대기시간을 함께 고려한 라우팅
같은 group_id 요청은 동일 워커에 유지해 LoRA 재로딩을 줄이되, 캐시 친화도가 전체 지연을 악화시키지 않도록 부하 가드를 함께 적용했습니다.
- group → worker 스티키 매핑에 TTL을 두고, queue+inflight가 임계치를 넘으면 최소 부하 워커로 우회
- 동률 워커는 round-robin으로 분산하고 burst 시 짧게 대기해 순간적인 한 워커 쏠림 완화
- studio → frontier → chat 순의 3단 source 우선순위 큐를 두고, 재시도·드레인 재배정에서도 등급 유지
- pool별 워커와 재시도 경로를 격리하고, 한 워커가 video 등 보조 풀에 참여할 수 있는 멤버십 지원
복구 가능한 상태·콜백 계약
- pending → queued → running → completed/failed/cancelled 상태와 terminal 여부를 API·콜백에서 동일하게 표현
- 콜백 실패를 Redis ZSET에 다음 시도 시각과 함께 기록하고 지수 백오프로 재전송
- ULID·터미널 상태 선점으로 poller와 GPU inbound callback의 동시 완료를 멱등 처리
- 콜백이 최종 실패해도
GET /v1/jobs/{ulid}와 최대 100건 배치 조회로 결과를 reconcile할 수 있는 안전망 제공 - queue_ms·dispatch_ms·comfy_exec_ms를 분리 기록해 엔진 대기와 실제 GPU 실행 병목을 구분
워커 생명주기와 안전한 셧다운
- 워커가 없는 풀은 사용자 대기형이면 즉시 503, 배치형이면 pending park 후 drain loop 재배정으로 정책 분리
- desired set과 supervisor reconcile로 워커 동적 합류·제거, 재시작 시 in-flight 상태 입양
- 그레이스풀 drain 시 신규 라우팅과 consumer를 멈추고 미제출 작업을 다른 워커로 옮긴 뒤 ComfyUI 내부 작업은 자연 완주
- dispatch timeout과 run timeout을 분리하고, Pacer로 ComfyUI 내부 queue depth를 제한해 과도한 VRAM 압력 완화
인프라 및 CI/CD
- 라우팅·콜백·레지스트리·Workflow Studio·타임아웃 회귀 테스트를 배포 선행 게이트로 실행
- GitHub Actions에서 Docker build → Artifact Registry push → GCE 배포·컨테이너 health check 자동화
- dev에서 검증한 컨테이너 이미지를 prod registry에 같은 artifact로 승격하고 환경별 Redis keyspace·GCS bucket 분리
Skills Acquired
- API 계약 — 스키마 기반 workflow 패키지, 버전·해시·입출력 계약 관리
- 분산 처리 — 다단 우선순위, 그룹 스티키, 부하 분산, 풀 격리와 그레이스풀 드레인
- Redis 모델링 — LIST/HASH/SET/ZSET을 이용한 큐·상태·재시도·워커 registry 설계
- 복구 설계 — 멱등 상태 전이, dual completion race, 콜백 재시도와 pull 기반 reconcile
- GPU 운영 — LoRA 캐시 재사용, Pacer, 실행시간 분해와 동적 워커 reconcile
Impact
- Poptale BFF와 Character Chat API의 이미지 실행을 하나의 엔진 계약으로 통합해 중복 graph·라우팅 코드 제거
- 호출자가 모델 경로와 ComfyUI node를 조립하지 않도록 해 워크플로 변경의 영향 범위를 엔진 내부로 제한
- 스티키·부하 가드·우선순위·Pacer를 함께 적용해 모델 캐시 재사용과 사용자 대기시간 사이의 정책을 명시화
- 재시도 가능한 콜백과 상태 조회 안전망으로 일시적 네트워크 장애 뒤에도 호출자가 최종 결과를 회수할 수 있게 함
- 드레인·desired reconcile로 GPU VM의 야간 셧다운 시 미제출 작업을 재배정하고 워커를 동적으로 합류시킬 기반 확보
회고
처음에는 BFF의 큐를 옮기는 작은 분리 작업이었지만, 두 제품이 같은 엔진을 사용하면서 진짜 경계는 “워크플로를 실행하는 곳”이 아니라 “실행 가능한 계약과 자산을 소유하는 곳”이라는 점을 배웠습니다. 그래서 graph, 입력 스키마, LoRA catalog, 출력 규약과 버전을 한 package로 관리하게 됐습니다.
또한 분산 시스템에서 “전송 성공”과 “작업 성공”은 다르다는 점을 상태 모델에 반영했습니다. push 콜백만 믿지 않고 pull 조회와 멱등 상태 전이를 함께 제공하고, 캐시 친화적 라우팅에도 부하 가드를 둔 경험은 효율성과 복구 가능성을 동시에 설계하는 기준이 됐습니다.