backend-hang-debug
Diagnose and fix FastAPI hangs
FastAPI applications can hang when ThreadPoolExecutor shutdown blocks the event loop, especially during SSE stream disconnects. This skill provides a repeatable triage workflow using py-spy to capture live stacks and apply non-blocking executor patterns to restore responsiveness.
์คํฌ ZIP ๋ค์ด๋ก๋
Claude์์ ์ ๋ก๋
์ค์ โ ๊ธฐ๋ฅ โ ์คํฌ โ ์คํฌ ์ ๋ก๋๋ก ์ด๋
ํ ๊ธ์ ์ผ๊ณ ์ฌ์ฉ ์์
ํ ์คํธํด ๋ณด๊ธฐ
"backend-hang-debug" ์ฌ์ฉ ์ค์ ๋๋ค. My FastAPI news stream route is causing the app to hang. Health checks timeout when streams are active.
์์ ๊ฒฐ๊ณผ:
- The hang is likely caused by ThreadPoolExecutor.shutdown(wait=True) blocking the event loop during client disconnects.
- 1. Capture live stacks with: sudo py-spy dump --pid $(pgrep -f 'uvicorn app.main')
- 2. Look for ThreadPoolExecutor.shutdown frames in api/routes/stream.py
- 3. Refactor to use non-blocking executor: Create executor outside context manager, use cancel() on disconnect, and call shutdown(wait=False, cancel_futures=True) in finally block.
- 4. Verify with: curl -m 5 http://localhost:8000/health during active stream
๋ณด์ ๊ฐ์ฌ
์์ This is a documentation-only skill containing markdown instructions for debugging FastAPI hangs. The static analyzer flagged 74 pattern matches, but all are false positives: the skill contains no executable code, scripts, network operations, or filesystem access beyond reading its own file. The 'commands' flagged are documentation examples showing diagnostic commands users might run on their own systems. Pure informational content safe for publication.
์ํ ์์ธ
โ๏ธ ์ธ๋ถ ๋ช ๋ น์ด (44)
๐ ๋คํธ์ํฌ ์ ๊ทผ (11)
๐ ํ์ผ ์์คํ ์ก์ธ์ค (3)
ํ์ง ์ ์
๋ง๋ค ์ ์๋ ๊ฒ
Debug production hangs
Diagnose why FastAPI app stops responding to health checks during active SSE stream connections
Triage event loop issues
Use py-spy to capture blocking stack frames and identify ThreadPoolExecutor.shutdown as the root cause
Fix stream disconnects
Implement non-blocking executor pattern so aborting stream requests does not freeze the backend
์ด ํ๋กฌํํธ๋ฅผ ์ฌ์ฉํด ๋ณด์ธ์
My FastAPI app stopped responding to requests. How do I use py-spy to find what's blocking the event loop?
I captured a py-spy dump and see ThreadPoolExecutor.shutdown in the frames. What does this mean and how do I fix it?
Help me refactor my stream.py to use a non-blocking ThreadPoolExecutor pattern that does not block on shutdown.
I applied the non-blocking executor pattern. How do I verify with py-spy that the event loop is no longer blocked?
๋ชจ๋ฒ ์ฌ๋ก
- Always use shutdown(wait=False, cancel_futures=True) for executors in async contexts to prevent event loop blocking.
- Capture py-spy stacks before restarting the service to preserve evidence of the blocking operation.
- Test stream abort scenarios during development to catch hangs early before production deployment.
ํผํ๊ธฐ
- Using 'with ThreadPoolExecutor()' as context manager in async code - it calls shutdown(wait=True) which blocks.
- Awaiting executor.shutdown() inside async functions - this synchronously blocks the event loop.
- Ignoring client disconnects without cancelling pending futures - they can hold resources and cause resource leaks.
์์ฃผ ๋ฌป๋ ์ง๋ฌธ
Which Python versions support the non-blocking executor pattern?
What are reasonable timeouts for curl smoke tests?
How do I integrate this with Docker deployments?
Does this skill collect any data from my system?
Why does my app hang only during stream disconnects?
How does this compare to using asyncio threads?
๊ฐ๋ฐ์ ์ธ๋ถ ์ ๋ณด
ํ์ผ ๊ตฌ์กฐ
๐ SKILL.md