Files
api-copp/bd/__init__.py
jze9 ab1788c57f refactor: удалить мёртвый код в bd/__init__.py
DATABASE_URL_asyncpg нигде не использовался — реально работает только
DATABASE_URL_syncpg/pg8000 через синхронный engine. validate_db_port был
не подключён как pydantic-валидатор (нет декоратора) и никогда не
вызывался — DB_PORT конвертируется строкой выше через голый int().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 11:54:21 +05:00

78 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Database configuration package
from pydantic import BaseModel
import os
import urllib.parse
class Settings(BaseModel):
DB_HOST: str = os.getenv("DB_HOST", "postgres")
DB_PORT: int = int(os.getenv("DB_PORT", "5432"))
DB_USER: str = os.getenv("DB_USER", "postgres")
DB_PASS: str = os.getenv("DB_PASS", "")
DB_NAME: str = os.getenv("DB_NAME", "profi")
@property
def DATABASE_URL_syncpg(self) -> str:
pwd = urllib.parse.quote_plus(str(self.DB_PASS))
return f"postgresql+pg8000://{self.DB_USER}:{pwd}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
@property
def PG8000_CONNECT_ARGS(self) -> dict:
"""connect_args для pg8000 — отключаем SSL (сервер его не поддерживает)."""
return {"ssl_context": None}
def make_engine():
"""Создаёт SQLAlchemy engine с правильными параметрами для pg8000."""
from sqlalchemy import create_engine
s = Settings()
return create_engine(
s.DATABASE_URL_syncpg,
connect_args=s.PG8000_CONNECT_ARGS,
future=True,
pool_pre_ping=True,
pool_size=5,
max_overflow=5,
pool_timeout=30,
pool_recycle=1800,
)
def wait_for_db(retries: int = 15, delay: float = 2.0) -> None:
"""Ждёт, пока PostgreSQL станет доступен. Вызывается при старте приложения."""
import time
import logging
from sqlalchemy import text
logger = logging.getLogger("bd")
engine = make_engine()
for attempt in range(1, retries + 1):
try:
with engine.connect() as conn:
conn.execute(text("SELECT 1"))
logger.info("PostgreSQL is ready.")
return
except Exception as exc:
logger.warning("DB not ready (attempt %d/%d): %s", attempt, retries, exc)
if attempt < retries:
time.sleep(delay)
raise RuntimeError("PostgreSQL did not become ready in time.")
# ── Singleton engine + session factory (один движок на весь процесс) ───────
_engine = None
_SessionFactory = None
def get_engine():
global _engine
if _engine is None:
_engine = make_engine()
return _engine
def get_session():
global _SessionFactory
if _SessionFactory is None:
from sqlalchemy.orm import sessionmaker
_SessionFactory = sessionmaker(bind=get_engine(), future=True)
return _SessionFactory