From 324c88e6528f6b1422537e8c20ab7fc53c47b3a3 Mon Sep 17 00:00:00 2001 From: yiekheng Date: Sun, 3 May 2026 10:56:17 +0800 Subject: [PATCH] fix(db): pool_size default 24 to fit transfer-bot's 20 worker threads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous default of 8 was a regression risk: cm_transfer_credit.py uses ThreadPoolExecutor with CM_TRANSFER_MAX_THREADS (default 20 in prod compose), so up to 20 threads concurrently call self.db.query(). With pool_size=8, the 9th-20th threads would hit PoolError, which gets caught by 'except Error' and silently returns []/False — making transfers fail with no obvious cause. Default bumped to 24 (covers the 20-thread default with 4 in reserve). mysql.connector caps pool_size at 32; clamping with a clear log line so a future operator who pushes CM_TRANSFER_MAX_THREADS too high gets a readable message instead of a library traceback. Operator note: if you raise CM_TRANSFER_MAX_THREADS, also raise DB_POOL_SIZE to at least the same value (max 32). At 32 threads with 4 services × 32 = 128 conns total, still well under MySQL's default max_connections=151. --- app/db.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/db.py b/app/db.py index 8798f9f..a0de3a8 100644 --- a/app/db.py +++ b/app/db.py @@ -20,6 +20,19 @@ _pool_lock = threading.Lock() def _build_pool() -> "pooling.MySQLConnectionPool": + # pool_size default of 24 covers transfer-bot at full tilt: + # CM_TRANSFER_MAX_THREADS defaults to 20, each thread can hold one + # connection for the duration of a transfer step. A smaller pool + # would surface as PoolError (caught silently by query/execute) and + # transfers would fail without obvious cause. mysql.connector caps + # pool_size at 32; if you bump CM_TRANSFER_MAX_THREADS, set + # DB_POOL_SIZE to at least the same value, capped at 32. + pool_size = int(os.getenv("DB_POOL_SIZE", "24")) + if pool_size > 32: + # Hard cap from mysql.connector; clamp here so the misconfigured + # value gets a clean message instead of a cryptic library error. + print(f"DB_POOL_SIZE={pool_size} exceeds mysql.connector max (32); clamping to 32") + pool_size = 32 config = { "host": _get_required_env("DB_HOST"), "user": _get_required_env("DB_USER"), @@ -28,7 +41,7 @@ def _build_pool() -> "pooling.MySQLConnectionPool": "port": int(_get_required_env("DB_PORT")), "connection_timeout": int(_get_required_env("DB_CONNECTION_TIMEOUT")), "pool_name": "cm_pool", - "pool_size": int(os.getenv("DB_POOL_SIZE", "8")), + "pool_size": pool_size, "pool_reset_session": True, } return pooling.MySQLConnectionPool(**config)