From 19236ecc9db82a05dcaec6a4f988888bf5e5b5b5 Mon Sep 17 00:00:00 2001 From: 9qeklajc Date: Fri, 31 Jul 2026 02:14:50 +0200 Subject: [PATCH] fix(db): increase default connection pool capacity --- .env.example | 6 +++--- routstr/core/settings.py | 14 +++++++------- tests/unit/test_settings.py | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.env.example b/.env.example index 9f0c0bbc..17ae6951 100644 --- a/.env.example +++ b/.env.example @@ -26,9 +26,9 @@ ROUTSTR_SECRET_KEY= # logged at startup. Keep total capacity across all workers below the database # connection limit. Pre-ping is automatic for networked backends; SQLite may # explicitly opt in if desired. -# DATABASE_POOL_SIZE=5 -# DATABASE_MAX_OVERFLOW=10 -# DATABASE_POOL_TIMEOUT=30 +# DATABASE_POOL_SIZE=10 +# DATABASE_MAX_OVERFLOW=20 +# DATABASE_POOL_TIMEOUT=15 # DATABASE_POOL_RECYCLE=1800 # DATABASE_POOL_PRE_PING=false # Warn when a checkout is held this many seconds. diff --git a/routstr/core/settings.py b/routstr/core/settings.py index 0caffd16..4674733a 100644 --- a/routstr/core/settings.py +++ b/routstr/core/settings.py @@ -106,14 +106,14 @@ class Settings(BaseSettings): default=900, gt=0, env="REFUND_SWEEP_CLAIM_TIMEOUT_SECONDS" ) - # Database connection-pool controls (advanced). Capacity defaults match - # SQLAlchemy's established queue-pool behavior. Pre-ping is enabled by the - # engine factory for networked backends; SQLite can explicitly opt in. - # These fields are env-only below. - database_pool_size: int = Field(default=5, ge=1, env="DATABASE_POOL_SIZE") - database_max_overflow: int = Field(default=10, ge=0, env="DATABASE_MAX_OVERFLOW") + # Database connection-pool controls (advanced). Capacity defaults provide + # headroom for Routstr's concurrent request and background-payment workload. + # Pre-ping is enabled by the engine factory for networked backends; SQLite + # can explicitly opt in. These fields are env-only below. + database_pool_size: int = Field(default=10, ge=1, env="DATABASE_POOL_SIZE") + database_max_overflow: int = Field(default=20, ge=0, env="DATABASE_MAX_OVERFLOW") database_pool_timeout: float = Field( - default=30.0, gt=0, env="DATABASE_POOL_TIMEOUT" + default=15.0, gt=0, env="DATABASE_POOL_TIMEOUT" ) database_pool_recycle: int = Field(default=1800, ge=0, env="DATABASE_POOL_RECYCLE") database_pool_pre_ping: bool = Field(default=False, env="DATABASE_POOL_PRE_PING") diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index 98a9e24f..34fa7101 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -62,11 +62,11 @@ def test_payout_settings_have_sensible_defaults() -> None: assert s.payout_interval_seconds == 900 -def test_database_pool_defaults_match_sqlalchemy_capacity() -> None: +def test_database_pool_defaults_provide_concurrency_headroom() -> None: s = Settings() - assert s.database_pool_size == 5 - assert s.database_max_overflow == 10 - assert s.database_pool_timeout == 30.0 + assert s.database_pool_size == 10 + assert s.database_max_overflow == 20 + assert s.database_pool_timeout == 15.0 assert s.database_pool_recycle == 1800 assert s.database_pool_pre_ping is False assert s.database_pool_hold_warn_seconds == 10.0 @@ -139,7 +139,7 @@ async def test_update_does_not_apply_env_only_fields_to_live_settings( from the running pool. """ monkeypatch.delenv("DATABASE_POOL_SIZE", raising=False) - monkeypatch.setattr(settings, "database_pool_size", 5) + monkeypatch.setattr(settings, "database_pool_size", 10) engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with AsyncSession(engine, expire_on_commit=False) as session: @@ -151,7 +151,7 @@ async def test_update_does_not_apply_env_only_fields_to_live_settings( # A non-env-only field still updates normally... assert settings.name == "PoolTweaker" # ...but the env-only pool size stays at the boot value. - assert settings.database_pool_size == 5 + assert settings.database_pool_size == 10 # ...and it is never written to the settings blob. blob = await _read_settings_blob(session) assert "database_pool_size" not in blob