diff --git a/app/database/session.py b/app/database/session.py index 6b914b3..8988c91 100644 --- a/app/database/session.py +++ b/app/database/session.py @@ -6,6 +6,8 @@ from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from sqlalchemy.orm import DeclarativeBase +from app.dashboard.exceptions import DashboardException +from app.social.exceptions import SocialException from app.utils.logger import get_logger from config import db_settings @@ -137,6 +139,16 @@ async def get_session() -> AsyncGenerator[AsyncSession, None]: yield session except HTTPException: raise + except (SocialException, DashboardException) as e: + # 전역 exception handler가 응답으로 변환하는 도메인 예외. + # 정상 플로우이므로 ERROR traceback 없이 롤백만 수행. + await session.rollback() + logger.warning( + f"[get_session] ROLLBACK - handled domain error: " + f"{type(e).__name__}: {e}, " + f"duration: {(time.perf_counter() - start_time)*1000:.1f}ms" + ) + raise except Exception as e: await session.rollback() logger.error(traceback.format_exc()) diff --git a/app/video/api/routers/v1/video.py b/app/video/api/routers/v1/video.py index b59b36c..9cc465b 100644 --- a/app/video/api/routers/v1/video.py +++ b/app/video/api/routers/v1/video.py @@ -356,6 +356,9 @@ async def generate_video( creatomate_service = CreatomateService( orientation=orientation, industry=industry, + # 미매핑 업종(general 등)은 project_id % len(VST_LIST)로 템플릿을 분배하므로, + # 사전 이미지 배정 단계(creative_assets_task)와 동일 템플릿을 받으려면 필수 + project_id=project_id, ) logger.debug( f"[generate_video] Using template_id: {creatomate_service.template_id}, (song duration: {song_duration})"