diff --git a/services/docker-compose.yml b/services/docker-compose.yml index 77dce0d..d81f9cf 100644 --- a/services/docker-compose.yml +++ b/services/docker-compose.yml @@ -49,3 +49,33 @@ services: interval: 60s timeout: 5s retries: 3 + + video-render: + build: + context: ./video-render + container_name: video-render + restart: unless-stopped + ports: + - "18712:8000" + environment: + - TZ=Asia/Seoul + - REDIS_URL=${REDIS_URL:-redis://192.168.45.54:6379} + - NAS_BASE_URL=${NAS_BASE_URL:-http://192.168.45.54:18801} + - INTERNAL_API_KEY=${INTERNAL_API_KEY:-} + - OPENAI_API_KEY=${OPENAI_API_KEY:-} + - GOOGLE_PROJECT_ID=${GOOGLE_PROJECT_ID:-} + - GOOGLE_LOCATION=${GOOGLE_LOCATION:-us-central1} + - GOOGLE_GCS_BUCKET=${GOOGLE_GCS_BUCKET:-} + - GOOGLE_APPLICATION_CREDENTIALS=/app/keys/gcp-sa.json + - PIAPI_API_KEY=${PIAPI_API_KEY:-} + - SEEDANCE_API_KEY=${SEEDANCE_API_KEY:-} + - VIDEO_MEDIA_ROOT=${VIDEO_MEDIA_ROOT:-/mnt/nas/webpage/data/video} + - VIDEO_MEDIA_URL_PREFIX=${VIDEO_MEDIA_URL_PREFIX:-/media/video} + volumes: + - /mnt/nas/webpage/data/video:/mnt/nas/webpage/data/video + - ${GCP_SA_JSON_HOST_PATH:-/etc/webai/gcp-sa.json}:/app/keys/gcp-sa.json:ro + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] + interval: 60s + timeout: 5s + retries: 3 diff --git a/services/video-render/main.py b/services/video-render/main.py new file mode 100644 index 0000000..4641de3 --- /dev/null +++ b/services/video-render/main.py @@ -0,0 +1,36 @@ +"""video-render FastAPI entry — health + lifespan (worker loop spawn).""" +from __future__ import annotations + +import asyncio +import logging +from contextlib import asynccontextmanager + +from fastapi import FastAPI + +import worker + +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(name)s %(levelname)s %(message)s") +logger = logging.getLogger(__name__) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + worker_task = asyncio.create_task(worker.worker_loop()) + logger.info("video-render lifespan 시작") + try: + yield + finally: + worker_task.cancel() + try: + await worker_task + except asyncio.CancelledError: + pass + logger.info("video-render lifespan 종료") + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/health") +def health(): + return {"ok": True, "service": "video-render"}