Spaces:
Sleeping
Sleeping
| from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession | |
| from sqlalchemy.orm import sessionmaker, declarative_base | |
| import os | |
| import socket | |
| import urllib.parse | |
| import ssl | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| # Changed to PostgreSQL connection for pgvector | |
| DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://fras_user:fras_password@127.0.0.1:5433/fras_db") | |
| connect_args = {} | |
| # Increase connection establishment timeout to 30 seconds to handle cold starts | |
| connect_args["timeout"] = 30 | |
| if DATABASE_URL: | |
| # 1. Clean query parameters (strip sslmode=require) | |
| if "?" in DATABASE_URL: | |
| base_url, query = DATABASE_URL.split("?", 1) | |
| params = [p for p in query.split("&") if not p.startswith("sslmode=")] | |
| if params: | |
| DATABASE_URL = base_url + "?" + "&".join(params) | |
| else: | |
| DATABASE_URL = base_url | |
| # 2. Resolve hostname to IPv4 to bypass IPv6 routing issues on local networks | |
| parsed = urllib.parse.urlparse(DATABASE_URL) | |
| hostname = parsed.hostname | |
| if hostname and not hostname.replace('.', '').isdigit(): | |
| try: | |
| ip_addresses = socket.getaddrinfo(hostname, parsed.port or 5432, family=socket.AF_INET) | |
| if ip_addresses: | |
| ipv4 = ip_addresses[0][4][0] | |
| # Replace hostname in netloc (handles username:password@host:port) | |
| netloc = parsed.netloc.replace(hostname, ipv4) | |
| DATABASE_URL = parsed._replace(netloc=netloc).geturl() | |
| # Pass Neon endpoint ID via server settings options to route direct IP connections | |
| if "neon.tech" in hostname or "neon.tech" in DATABASE_URL: | |
| endpoint_id = hostname.split('.')[0] | |
| connect_args["server_settings"] = { | |
| "options": f"endpoint={endpoint_id}" | |
| } | |
| except Exception: | |
| pass | |
| # 3. Enable SSL and bypass hostname validation if using Neon | |
| if "neon.tech" in os.getenv("DATABASE_URL", "") or "neon.tech" in DATABASE_URL or (hostname and "neon.tech" in hostname): | |
| ssl_context = ssl.create_default_context() | |
| ssl_context.check_hostname = False | |
| ssl_context.verify_mode = ssl.CERT_NONE | |
| connect_args["ssl"] = ssl_context | |
| engine = create_async_engine( | |
| DATABASE_URL, | |
| echo=False, | |
| connect_args=connect_args, | |
| pool_pre_ping=True, | |
| pool_recycle=300 | |
| ) | |
| AsyncSessionLocal = sessionmaker( | |
| engine, class_=AsyncSession, expire_on_commit=False | |
| ) | |
| Base = declarative_base() | |
| async def get_db(): | |
| async with AsyncSessionLocal() as session: | |
| yield session | |