This commit is contained in:
2026-02-11 11:05:41 +03:00
parent c8c9615f25
commit a93526c12c
2 changed files with 45 additions and 10 deletions

View File

@ -1,9 +1,11 @@
"""Database models and session management."""
import asyncio
from typing import AsyncGenerator
from sqlalchemy import create_engine, BigInteger, String, Integer, Boolean, ForeignKey, Column
from sqlalchemy.orm import declarative_base, sessionmaker, relationship, Session
from sqlalchemy.schema import UniqueConstraint
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
import socket
from bot.config import Config
from bot.logger import get_logger
@ -68,7 +70,23 @@ class UserChat(Base):
# Database engine and session (async)
# Convert postgresql:// to postgresql+asyncpg://
async_database_url = Config.DATABASE_URL.replace("postgresql://", "postgresql+asyncpg://", 1)
async_engine = create_async_engine(async_database_url, echo=False)
# Configure connection pool with better timeout settings
async_engine = create_async_engine(
async_database_url,
echo=False,
pool_pre_ping=True, # Verify connections before using them
pool_size=5, # Number of connections to maintain
max_overflow=10, # Maximum overflow connections
pool_recycle=3600, # Recycle connections after 1 hour
pool_timeout=30, # Timeout for getting connection from pool
connect_args={
"server_settings": {
"application_name": "bdbot",
},
"command_timeout": 60, # Command timeout
}
)
AsyncSessionLocal = async_sessionmaker(async_engine, class_=AsyncSession, expire_on_commit=False)
@ -82,15 +100,33 @@ async def get_db() -> AsyncGenerator[AsyncSession, None]:
async def init_db() -> None:
"""Initialize database - create all tables."""
"""Initialize database - create all tables with retry logic."""
logger.info("Initializing database...")
try:
async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
logger.info("Database initialized successfully")
except Exception as e:
logger.error(f"Error initializing database: {e}", exc_info=True)
raise
max_retries = 5
base_delay = 2 # Start with 2 seconds
for attempt in range(max_retries):
try:
async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
logger.info("Database initialized successfully")
return
except (socket.gaierror, OSError) as e:
# DNS resolution or network errors
if attempt < max_retries - 1:
delay = base_delay * (2 ** attempt) # Exponential backoff: 2, 4, 8, 16, 32
logger.warning(
f"Database connection failed (attempt {attempt + 1}/{max_retries}): {e}. "
f"Retrying in {delay} seconds..."
)
await asyncio.sleep(delay)
else:
logger.error(f"Failed to connect to database after {max_retries} attempts: {e}", exc_info=True)
raise
except Exception as e:
logger.error(f"Error initializing database: {e}", exc_info=True)
raise
def get_db_session():

View File

@ -1 +0,0 @@
# Handlers package