FastAPI-based scraper for commodity ticker prices (HO, CL, RB futures) and competitor oil pricing from NewEnglandOil. Includes cron-driven scraping, PostgreSQL storage, and REST endpoints for price retrieval. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
89 lines
2.0 KiB
Python
89 lines
2.0 KiB
Python
import logging
|
|
import sys
|
|
from contextlib import contextmanager
|
|
from typing import Generator
|
|
|
|
from sqlalchemy import create_engine, text
|
|
from sqlalchemy.orm import sessionmaker, Session
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
from app.config import (
|
|
DATABASE_URL,
|
|
LOG_LEVEL,
|
|
LOG_FORMAT,
|
|
)
|
|
|
|
# =============================================================================
|
|
# LOGGING CONFIGURATION
|
|
# =============================================================================
|
|
|
|
logging.basicConfig(
|
|
level=getattr(logging, LOG_LEVEL.upper(), logging.INFO),
|
|
format=LOG_FORMAT,
|
|
handlers=[
|
|
logging.StreamHandler(sys.stdout),
|
|
]
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# =============================================================================
|
|
# DATABASE SETUP
|
|
# =============================================================================
|
|
|
|
# Create SQLAlchemy engine with connection pooling
|
|
engine = create_engine(
|
|
DATABASE_URL,
|
|
pool_pre_ping=True, # Verify connections before use
|
|
pool_size=5,
|
|
max_overflow=10,
|
|
echo=False, # Set to True for SQL debugging
|
|
)
|
|
|
|
# Session factory
|
|
SessionLocal = sessionmaker(
|
|
autocommit=False,
|
|
autoflush=False,
|
|
bind=engine,
|
|
)
|
|
|
|
|
|
def get_db() -> Generator[Session, None, None]:
|
|
"""
|
|
Dependency that provides a database session.
|
|
|
|
Yields a SQLAlchemy session and ensures proper cleanup.
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@contextmanager
|
|
def get_db_session() -> Generator[Session, None, None]:
|
|
"""
|
|
Context manager for database sessions (non-dependency use).
|
|
"""
|
|
db = SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def check_db_connection() -> bool:
|
|
"""
|
|
Test database connectivity.
|
|
|
|
Returns:
|
|
True if database is reachable, False otherwise
|
|
"""
|
|
try:
|
|
with get_db_session() as db:
|
|
db.execute(text("SELECT 1"))
|
|
return True
|
|
except SQLAlchemyError as e:
|
|
logger.error(f"Database connection failed: {e}")
|
|
return False
|