Previously sqlorContext only discarded connections on RuntimeError/OSError
('closed'/'handler is closed'). MySQL OperationalError (2014 Command Out of
Sync) and InterfaceError (0 Not connected) were not caught, causing dead
connections to be returned to the pool and reused — cascading to multiple
500 errors on /llmage/v1/chat/completions.
Now catches any Exception with known MySQL dead-connection messages
(Not connected, Command Out of Sync, Lost connection, Connection reset,
Server disconnected) and discards the connection.
Added tests: mysql_error_during_use (5 variants), business_error_not_discarded.
Add CHECK_ALIVE_THRESHOLD to avoid unnecessary DB round-trips when
reusing warm connections. Fixes connection storm under high concurrency
where 57% of logs were 'discarding dead connection'.
- Add _check_alive() to verify connections before yielding from pool
- Discard dead connections and create fresh ones automatically
- Add _discard_sqlor() helper to safely remove broken connections
- Detect and handle 'closed'/'handler is closed' RuntimeError during use
- Add unit test for connection discard behavior
Problem: High-concurrency streaming requests with client disconnects trigger
asyncio.CancelledError (BaseException in Python 3.8+), but exception handlers
only caught Exception, causing:
- yielded_sqlor.used permanently stays True
- sqlor.exit() never called
- Connection slots permanently consumed, eventual pool exhaustion
Fix:
1. SqlorPool.context(): Use try/finally instead of try/except to always
reset yielded_sqlor.used=False, even on CancelledError
2. DBPools.sqlorContext(): Change except Exception to except BaseException,
add finally block to always call sqlor.exit(), suppress CancelledError
logging noise
Verification: Ad-hoc tests confirm connections properly reset on cancellation
and can be reused. Normal exceptions still propagate correctly.
Remove test_sqlor() validation from SqlorPool.context() which was causing:
- Every request to test ALL idle connections with SELECT 1
- Healthy connections being incorrectly deleted due to timeout under load
- Race conditions when multiple requests test the same connection
- Excessive connection creation leading to 501 Sleep connections
The new logic takes the first available connection without validation.
If a connection fails during actual use, the exception propagates naturally.