Fix new services implementation 9

This commit is contained in:
Urtzi Alfaro
2025-08-16 08:00:52 +02:00
parent 055ce10c66
commit 9de0f9943c
5 changed files with 37 additions and 83 deletions

View File

@@ -3,75 +3,18 @@
Database configuration and session management for Recipe Service Database configuration and session management for Recipe Service
""" """
from sqlalchemy import create_engine from shared.database.base import DatabaseManager, create_database_manager
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.pool import StaticPool
from contextlib import contextmanager
from typing import Generator
from .config import settings from .config import settings
# Create database manager using shared async infrastructure
# Create database engine db_manager = create_database_manager(
engine = create_engine( database_url=settings.DATABASE_URL,
settings.DATABASE_URL, service_name="recipes-service",
poolclass=StaticPool, echo=settings.DEBUG
pool_pre_ping=True,
pool_recycle=300,
echo=settings.DEBUG,
) )
# Create session factory # Dependency for FastAPI routes
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) async def get_db():
"""FastAPI dependency to get database session"""
async for session in db_manager.get_db():
def get_db() -> Generator[Session, None, None]: yield session
"""
Dependency to get database session
"""
db = SessionLocal()
try:
yield db
finally:
db.close()
@contextmanager
def get_db_context() -> Generator[Session, None, None]:
"""
Context manager for database session
"""
db = SessionLocal()
try:
yield db
db.commit()
except Exception:
db.rollback()
raise
finally:
db.close()
class DatabaseManager:
"""Database management utilities"""
@staticmethod
def create_all_tables():
"""Create all database tables"""
from shared.database.base import Base
Base.metadata.create_all(bind=engine)
@staticmethod
def drop_all_tables():
"""Drop all database tables (for testing)"""
from shared.database.base import Base
Base.metadata.drop_all(bind=engine)
@staticmethod
def get_session() -> Session:
"""Get a new database session"""
return SessionLocal()
# Database manager instance
db_manager = DatabaseManager()

View File

@@ -15,6 +15,8 @@ from contextlib import asynccontextmanager
from .core.config import settings from .core.config import settings
from .core.database import db_manager from .core.database import db_manager
from .api import recipes, production, ingredients from .api import recipes, production, ingredients
# Import models to register them with SQLAlchemy metadata
from .models import recipes as recipe_models
# Configure logging # Configure logging
@@ -33,7 +35,7 @@ async def lifespan(app: FastAPI):
# Create database tables # Create database tables
try: try:
db_manager.create_all_tables() await db_manager.create_tables()
logger.info("Database tables created successfully") logger.info("Database tables created successfully")
except Exception as e: except Exception as e:
logger.error(f"Failed to create database tables: {e}") logger.error(f"Failed to create database tables: {e}")
@@ -97,17 +99,14 @@ async def health_check():
"""Health check endpoint""" """Health check endpoint"""
try: try:
# Test database connection # Test database connection
db = db_manager.get_session() health_result = await db_manager.health_check()
try:
db.execute("SELECT 1")
finally:
db.close()
return { return {
"status": "healthy", "status": "healthy",
"service": settings.SERVICE_NAME, "service": settings.SERVICE_NAME,
"version": settings.SERVICE_VERSION, "version": settings.SERVICE_VERSION,
"environment": settings.ENVIRONMENT "environment": settings.ENVIRONMENT,
"database": health_result
} }
except Exception as e: except Exception as e:
logger.error(f"Health check failed: {e}") logger.error(f"Health check failed: {e}")

View File

@@ -505,7 +505,11 @@ class AIOnboardingService:
"description": modifications.get("description") or approval.get("notes", ""), "description": modifications.get("description") or approval.get("notes", ""),
# Optional fields # Optional fields
"brand": modifications.get("brand") or approval.get("suggested_supplier"), "brand": modifications.get("brand") or approval.get("suggested_supplier"),
"is_active": True "is_active": True,
# Explicitly set boolean fields to ensure they're not NULL
"requires_refrigeration": modifications.get("requires_refrigeration", approval.get("requires_refrigeration", False)),
"requires_freezing": modifications.get("requires_freezing", approval.get("requires_freezing", False)),
"is_perishable": modifications.get("is_perishable", approval.get("is_perishable", False))
} }
# Add optional numeric fields only if they exist # Add optional numeric fields only if they exist

View File

@@ -32,10 +32,6 @@ async def lifespan(app: FastAPI):
await init_db() await init_db()
logger.info("Database initialized successfully") logger.info("Database initialized successfully")
# Setup metrics
setup_metrics_early(app, "suppliers-service")
logger.info("Metrics setup completed")
yield yield
except Exception as e: except Exception as e:
@@ -72,6 +68,12 @@ app.add_middleware(
allow_headers=["*"], allow_headers=["*"],
) )
# Setup metrics
try:
setup_metrics_early(app, "suppliers-service")
logger.info("Metrics setup completed")
except Exception as e:
logger.error("Metrics setup failed", error=str(e))
# Setup authentication middleware (commented out - not implemented) # Setup authentication middleware (commented out - not implemented)
# setup_auth_middleware(app) # setup_auth_middleware(app)

View File

@@ -154,11 +154,17 @@ class DatabaseManager:
try: try:
target_metadata = metadata or Base.metadata target_metadata = metadata or Base.metadata
async with self.async_engine.begin() as conn: async with self.async_engine.begin() as conn:
await conn.run_sync(target_metadata.create_all) await conn.run_sync(target_metadata.create_all, checkfirst=True)
logger.info("Database tables created successfully", service=self.service_name) logger.info("Database tables created successfully", service=self.service_name)
except Exception as e: except Exception as e:
logger.error(f"Failed to create tables: {e}", service=self.service_name) # Check if it's a "relation already exists" error which can be safely ignored
raise DatabaseError(f"Table creation failed: {str(e)}") error_str = str(e).lower()
if "already exists" in error_str or "duplicate" in error_str:
logger.warning(f"Some database objects already exist - continuing: {e}", service=self.service_name)
logger.info("Database tables creation completed (some already existed)", service=self.service_name)
else:
logger.error(f"Failed to create tables: {e}", service=self.service_name)
raise DatabaseError(f"Table creation failed: {str(e)}")
async def drop_tables(self, metadata=None): async def drop_tables(self, metadata=None):
"""Drop database tables""" """Drop database tables"""