feat: make the telemetry pool declare what it costs

The pool was the only external resource in the library that pre-allocated:
asyncpg's default min_size=10 turned pool creation into an all-or-nothing
action, so on a shared instance running low on connection budget the first
thing to fall over was the one component that must not fail silently
(4 clients x 10 = 40 idle connections just to write telemetry).

min_size=0 means "do not pre-connect" - asyncpg only builds holders - so
pool creation becomes free and never touches the database; connection
failures then land on acquire, the path that already drops one row and lets
the pool recover. max_size and the write budget become the library's
explicit statement about its own footprint, configurable through two new
keys whose defaults live in config alone (the recorder parameters are
required keyword-only, same discipline as auto_migrate).

The whole write - prepare, acquire, execute - now runs inside one
asyncio.timeout: acquire used to have no timeout at all, so a full pool
would hang forever on the caller's path. Release is explicit rather than
`async with`, because asyncpg shields release and reuses the acquire
timeout, which would let a single telemetry write consume twice the budget.
This commit is contained in:
2026-08-24 09:32:35 -04:00
parent f958138e83
commit 84c2cc11a4
6 changed files with 450 additions and 43 deletions
+4 -1
View File
@@ -483,7 +483,10 @@ def _build_telemetry(settings: GatewaySettings) -> TelemetryRecorder | None:
assert settings.telemetry_pg_dsn is not None # 内部不变量: _validate_telemetry 已保证
return PostgresRecorder(
settings.telemetry_pg_dsn, auto_migrate=settings.telemetry_auto_migrate
settings.telemetry_pg_dsn,
auto_migrate=settings.telemetry_auto_migrate,
pool_max=settings.telemetry_pg_pool_max,
write_timeout_s=settings.telemetry_pg_write_timeout_s,
)
from polygateway.telemetry.sqlite import SQLiteRecorder