Spaces:
Running
Running
File size: 1,841 Bytes
de28957 be24846 de28957 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | from __future__ import annotations
from contextlib import asynccontextmanager
from psycopg_pool import AsyncConnectionPool
from app.config import get_settings
_pool: AsyncConnectionPool | None = None
def get_pool() -> AsyncConnectionPool:
global _pool
if _pool is None:
settings = get_settings()
_pool = AsyncConnectionPool(
conninfo=settings.postgres_readonly_url,
min_size=1,
max_size=10,
open=False,
# --- ADDED TO FIX CROSS-CLOUD SSL DROPS ---
max_idle=30.0, # Recycle connections that sit silent for over 30s
check=AsyncConnectionPool.check_connection, # Test the connection health before handing it to your tool
kwargs={
"keepalives": 1, # Turn on TCP Keepalives
"keepalives_idle": 30, # Ping Railway every 30 seconds of silence
"keepalives_interval": 10, # If a ping fails, retry every 10 seconds
"keepalives_count": 5, # Drop the socket if 5 pings fail in a row
},
)
return _pool
async def open_pool() -> None:
"""Call on app startup."""
pool = get_pool()
if pool.closed:
await pool.open(wait=True)
async def close_pool() -> None:
"""Call on app shutdown."""
global _pool
if _pool is not None and not _pool.closed:
await _pool.close()
_pool = None
@asynccontextmanager
async def get_readonly_connection():
"""
Yields a connection with an extra read-only guard set at the
session level, on top of the chat_ro_user DB role.
"""
pool = get_pool()
async with pool.connection() as conn:
await conn.execute("SET default_transaction_read_only = on")
yield conn |