# DB Connection Pool Singleton Hotfix (2026-04-30)

## 背景

`/daily_sales` 出現 PostgreSQL `FATAL: sorry, too many clients already`。根因不是單一查詢過重，而是多個 route 會在 request 內直接呼叫 `DatabaseManager()`，舊實作每次初始化都 `create_engine()`，導致同一個 worker process 內反覆建立新的 SQLAlchemy connection pool。

## 修正

`database/manager.py` 的 `DatabaseManager` 以 `(DATABASE_TYPE, effective_db_path)` 作為 key 快取 `engine` 與 `Session` factory。後續直接 `DatabaseManager()` 會共用同一組連線池，不再持續放大 PostgreSQL client 數。

第二輪硬化：

- 將「查快取 + 建立 engine」放在同一把 lock 內，避免併發第一波 request 同時建立多個 pool。
- PostgreSQL pool 從 `pool_size=5, max_overflow=10` 收斂為 `pool_size=2, max_overflow=3`，降低 gunicorn 多 worker 下的總連線上限。

## 維運提醒

- 若再次遇到 `too many clients already`，先檢查是否有新模組繞過 `database.manager.get_db_manager()` 或直接 `create_engine()`。
- 熱修後需重啟 `momo-pro-system`，讓舊 process 釋放既有連線池。
- 不需要重啟或重建 `momo-db`。
- 用容器內 Flask test client 塞入 `logged_in=True` session，可直接 smoke `/daily_sales` 真實查詢路徑；未登入 curl 只會測到 301/登入頁。
