증상:
- 라이브 smoke 도중 SSE poll loop 가 0.5s 마다 connection 을 빌리던 중,
asyncpg pool 이 idle/network blip 으로 socket 이 닫힌 stale connection
을 그대로 넘김. 다음 요청 (GET /api/sessions) 이
`sqlalchemy.exc.InterfaceError: connection is closed` 로 500.
원인:
- `create_async_engine(database_url, poolclass=None, echo=False)` —
pool_pre_ping 미설정. SQLAlchemy 가 checkout 시 connection 생존
확인 안 함.
수정:
- `pool_pre_ping=True` 한 줄 추가. SQLAlchemy 가 매 checkout 직전 빠른
SELECT 1 (asyncpg 는 protocol-level ping) 을 보내고 실패 시 pool 에서
invalidate 후 새 connection 발급. 표준 SQLAlchemy 권장 패턴.
- 부하 (SSE 0.5s polling + REST) 에서 검증: 재시작 후 GET /api/sessions
연속 호출 모두 200.
테스트:
- ruff / mypy: PASS (141 files)
- pytest tests/integration/test_persistence.py: 20 passed (회귀 없음)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>