Spaces:
Sleeping
Sleeping
Commit ·
d0ce1e8
1
Parent(s): f4bb922
fix(deploy): auto-disable prepared statements on Supabase pooler
Browse filesasyncpg's DuplicatePreparedStatementError fires when running against
PgBouncer in transaction-pool mode (Supabase shared pooler). The
DB_USE_PGBOUNCER env was already wired but easy to forget on deploy.
Auto-detect Supabase pooler from the URL (port 6543 or
pooler.supabase.com host) and force statement_cache_size=0 +
prepared_statement_cache_size=0. Explicit DB_USE_PGBOUNCER=true still
honoured for other PgBouncer deployments.
Fixes: prepared statement "__asyncpg_stmt_1__" already exists during
alembic upgrade head on Render.
services/backend/database.py
CHANGED
|
@@ -111,7 +111,14 @@ _MAX_OVERFLOW = int(os.getenv("DB_MAX_OVERFLOW", "20"))
|
|
| 111 |
_POOL_TIMEOUT = int(os.getenv("DB_POOL_TIMEOUT", "30"))
|
| 112 |
_POOL_RECYCLE = int(os.getenv("DB_POOL_RECYCLE", "1800"))
|
| 113 |
_SQL_ECHO = os.getenv("DB_ECHO", "false").lower() == "true"
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
|
| 117 |
def _create_engine(url: str = DATABASE_URL) -> AsyncEngine:
|
|
|
|
| 111 |
_POOL_TIMEOUT = int(os.getenv("DB_POOL_TIMEOUT", "30"))
|
| 112 |
_POOL_RECYCLE = int(os.getenv("DB_POOL_RECYCLE", "1800"))
|
| 113 |
_SQL_ECHO = os.getenv("DB_ECHO", "false").lower() == "true"
|
| 114 |
+
# Auto-detect: any Supabase pooler URL (port 6543 or "pooler.supabase.com" in host)
|
| 115 |
+
# implies pgBouncer transaction mode → prepared statements MUST be disabled.
|
| 116 |
+
# Explicit DB_USE_PGBOUNCER=true still wins for non-Supabase pgBouncer setups.
|
| 117 |
+
_USE_PGBOUNCER = (
|
| 118 |
+
os.getenv("DB_USE_PGBOUNCER", "false").lower() == "true"
|
| 119 |
+
or ":6543/" in DATABASE_URL
|
| 120 |
+
or "pooler.supabase.com" in DATABASE_URL
|
| 121 |
+
)
|
| 122 |
|
| 123 |
|
| 124 |
def _create_engine(url: str = DATABASE_URL) -> AsyncEngine:
|