osint-dashboard/app/database.py

33 lines
1.2 KiB
Python
Raw Normal View History

import os
2026-06-04 20:30:04 -04:00
from sqlalchemy import MetaData, event, text
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.pool import NullPool
2026-06-04 20:30:04 -04:00
from config import DATABASE_URL
2026-06-04 20:30:04 -04:00
# Pooled connections are bound to the event loop they were created on. Long-lived
# servers (uvicorn, the ingester) want a pool; short-lived / test processes that
# open a fresh event loop per unit (asyncio.run, pytest) must not reuse pooled
# connections across loops, so allow a NullPool (new connection per session).
_NULL_POOL = os.getenv("DB_NULL_POOL", "").lower() in ("1", "true", "yes")
2026-06-04 20:30:04 -04:00
engine = create_async_engine(
DATABASE_URL,
echo=False,
**({"poolclass": NullPool} if _NULL_POOL else
{"pool_size": 5, "max_overflow": 10, "pool_recycle": 300}),
2026-06-04 20:30:04 -04:00
)
async_session = async_sessionmaker(
engine, class_=AsyncSession, expire_on_commit=False
)
metadata = MetaData()
async def init_extensions():
"""Initialize PostGIS and TimescaleDB extensions on first connection."""
async with engine.connect() as conn:
await conn.execute(text("CREATE EXTENSION IF NOT EXISTS postgis"))
await conn.execute(text("CREATE EXTENSION IF NOT EXISTS timescaledb"))
await conn.commit()