Agent skill · software engineering · aiskillstore

backend-hang-debug

Diagnose and fix FastAPI hangs caused by blocking ThreadPoolExecutor shutdown in the news stream route; includes py-spy capture and non-blocking executor pattern.

Why this skill is useful

Provides a detailed non-blocking executor pattern for FastAPI that the AI wouldn't reliably generate on its own.

What it needs

Requires py-spy installed locally. About 2k tokens when loaded. Last updated 2026-08-07. 405 stars on the source repository.

What this skill does

Backend Hang Debug Purpose Detect and resolve event-loop hangs where the FastAPI app stops responding (e.g., curl http://localhost:8000/ times out) due to synchronous executor shutdown in the SSE news stream. Provide a repeatable triage flow using py-spy to capture live stacks and pinpoint blocking code. Scope Backend: backend/app/api/routes/stream.py (news stream), backend/app/services/rssingestion.py (RSS workers), startup processes. Tooling: py-spy for live stack dumps; curl with timeouts for smoke tests. Quick Triage 1. Reproduce hang: curl -m 5 http://localhost:8000/ and curl -m 5 http://localhost:8000/health; note timeouts. 2. Process check: ss -tlnp grep 8000 to confirm listener; ls /proc/$(pgrep -f "uvicorn app.main")/fd wc -l to rule out FD leak. 3. Stack capture (inside backend venv): uv pip install py-spy then sudo /home/bender/classwork/Thesis/backend/.venv/bin/py-spy dump --pid $(pgrep -f "uvicorn app.main") (and worker pid if multiprocess). Look for ThreadPoolExecutor.shutdown in api/routes/stream.py frames. Fix Pattern (non-blocking executor) Replace synchronous context manager with ThreadPoolExecutor(...): inside eventgenerator with a long-lived executor plus explicit non-blocking shutdown: Create executor outside the context manager. On client disconnect, cancel pending futures instead of awaiting shutdown. In finally, call executor.shutdown(wait=False, cancelfutures=True). Rationale: context manager calls shutdown(wait=True), blocking the event loop if RSS worker threads hang on network I/O. Implementation Steps 1. Update stream executor usage in backend/app/api/routes/stream.py: Instantiate executor = concurrent.futures.ThreadPoolExecutor(maxworkers=5). Dispatch work via loop.runinexecutor(executor, processsourcewithdebug, ...). On disconnect, cancel() pending futures. In finally, executor.shutdown(wait=False, cancelfutures=True). 2. …

How to use it

Reference it in AdaL, Claude Code, Cursor or any coding agent — nothing to install:

@skills aiskillstore/backend-hang-debug

View the source on GitHub

Browse the @skills marketplace