다크 모드
아키텍처
truloop-ai-server의 FastAPI + Celery 아키텍처, Service Layer 패턴, 요청 처리 흐름을 설명합니다.
아키텍처 다이어그램
아키텍처 패턴
Service Layer Pattern
비즈니스 로직을 서비스 클래스에 캡슐화하여 API 엔드포인트와 분리합니다.
| 계층 | 책임 |
|---|---|
| API Route | HTTP 요청 파싱, 응답 구성, DI |
| Service | 비즈니스 로직, AI 호출, 태스크 발행 |
| Model | DB 접근 (SQLAlchemy ORM) |
| Schema | 입출력 데이터 검증 (Pydantic) |
Repository Pattern
SQLAlchemy 모델을 통해 DB 접근을 추상화합니다. FastAPI의 Depends()를 통해 DB 세션을 주입합니다.
python
# FastAPI의 Depends() 기반 DI
@router.post("/generate")
async def generate(
request: GenerateRequest,
db: Session = Depends(get_db),
):
service = ContentGenerationService(db)
return await service.generate_content(...)요청 처리 흐름
동기 흐름 (즉시 응답)
비동기 흐름 (Celery 태스크 + Junis 웹훅)
미들웨어 구성
| 미들웨어 | 역할 |
|---|---|
SessionMiddleware | 세션 관리 (Admin UI) |
MetricsMiddleware | Prometheus 요청 메트릭 수집 |
CORSMiddleware | CORS 설정 |
시작 프로세스
콘텐츠 생성 흐름
주요 서비스
| 서비스 | 파일 | 역할 |
|---|---|---|
ContentGenerationService | content_generation_service.py | 콘텐츠 생성 오케스트레이션 (태스크 발행, 미디어 선택, Junis 요청) |
ContentTemplateService | content_template_service.py | 템플릿 CRUD |
BestImageSelector | best_image_selector.py | AI 기반 최적 이미지 선택 (토너먼트 방식, 이미지 URL 직접 전달) |
JunisContentGenerator | junis_content_generator.py | Junis AI API 연동 (웹훅 기반 비동기) |
ImageAnalysisService | image_analysis_service.py | Claude 기반 이미지 분석/설명/태깅 |
MediaService | media/media_service.py | DB 조회 전용 미디어 서비스 (LoopMedia 읽기) |
MediaUploadClient | media/media_upload_client.py | 외부 Media API 업로드 클라이언트 |
NotificationService | notification/notification_service.py | 알림 서비스 (현재 mock 구현) |
ClaudeRateLimiter | common/rate_limiter.py | 동시 요청/분당 요청 Rate Limiter |
TaskRegistry | core/task_registry.py | 중앙집중식 Celery Task 관리 (순환 import 방지) |
콘텐츠 타입별 처리
| 콘텐츠 타입 | TemplateType Enum | Celery Queue | 설명 |
|---|---|---|---|
| 일반/스토리 | story | content_generation | 텍스트 기반 스토리 콘텐츠 (블록 JSON) |
| 하이라이트 | highlight_default, highlight_style, highlight_tone | highlight_generation | 이미지 기반 하이라이트 비디오 |
| 포스터 | poster_style, poster_tone | poster_generation | AI 이미지 포스터 |
환경 설정
주요 환경변수
| 환경변수 | 설명 |
|---|---|
DATABASE_URL | PostgreSQL 연결 문자열 (postgresql+psycopg://) |
DATABASE_POOL_SIZE / DATABASE_MAX_OVERFLOW | DB 커넥션 풀 설정 (기본: 10/20) |
VALKEY_URL / VALKEY_HOST + VALKEY_PORT | Redis/Valkey 연결 |
OPENROUTER_API_KEY | OpenRouter API 키 (Claude LLM 호출) |
JUNIS_API_KEY / JUNIS_DOMAIN | Junis AI 콘텐츠 생성 서비스 |
MEDIA_API_BASE_URL | Media API 업로드 엔드포인트 |
AWS_* | AWS 자격 증명 (S3) |
S3_BUCKET | S3 버킷 이름 |
API_BASE_PATH | API 경로 prefix (기본: 빈 문자열) |
API_BASE_URL | 웹훅 콜백 URL 생성용 (Junis AI) |
ENV | 환경 모드 (development/staging/production) |
SENTRY_DSN | Sentry 에러 추적 |
ADMIN_SECRET_KEY | Admin 세션 비밀 키 |
REPLICATE_API_TOKEN | Replicate API 키 |
헬스체크
/health 엔드포인트에서 DB와 Redis 연결 상태를 동시에 확인합니다:
- 각 체크에 1.5초 타임아웃 적용
asyncio.gather()로 병렬 실행- 모든 체크 통과 시 200 OK, 하나라도 실패 시 503 Service Unavailable
json
{
"status": "ready",
"checks": {
"database": { "status": "healthy" },
"redis": { "status": "healthy" }
},
"response_time_ms": 45.2
}배포
ECS Fargate (ARM64)
FastAPI 서버와 Celery Worker 모두 ECS Fargate ARM64 (Graviton) 환경에서 실행됩니다.
| 항목 | FastAPI | Celery Worker |
|---|---|---|
| 아키텍처 | ARM64 (Graviton) | ARM64 (Graviton) |
| CPU | 512 (0.5 vCPU) | 512 (0.5 vCPU) |
| 메모리 | 1024 MB | 1024 MB |
| Desired Count | Dev: 1, Prod: 2 | Dev: 1, Prod: 2 |
Docker 빌드
bash
docker buildx build --platform linux/arm64 -t truloop-ai-server:latest .Celery Worker 설정
| 환경변수 | 기본값 | 설명 |
|---|---|---|
CELERY_CONCURRENCY | 2 | 워커 동시 처리 수 (0.5 vCPU/1GB 기준) |
CELERY_PREFETCH_MULTIPLIER | 1 | 워커당 프리페치 태스크 수 |
CELERY_MAX_TASKS_PER_CHILD | 1000 | 워커 프로세스 재시작 주기 |
정보
CELERY_CONCURRENCY는 Pulumi ESC에서 환경별로 재정의할 수 있습니다. I/O-bound 작업이므로 CPU보다 메모리가 제약 요소이며, 워커당 약 80-100MB 메모리를 사용합니다.
변경 이력
| 날짜 | 내용 |
|---|---|
| 2026-03-11 | ECS Fargate ARM64 (Graviton) 전환, 리소스 최적화 (CPU 2048→512, Memory 4096→1024), BestImageSelector 이미지 URL 직접 전달 반영 |
| 2026-03-10 | 최초 작성 |