19 views
When a worker stops answering health checks but CPU is idle, you are usually in a lock graph—not a “slow query.” The unfair advantage is dumping all Python threads with faulthandler and, when that is silent, attaching gdb for native frames inside C extensions.
⚡ TL;DR: Enablefaulthandlerdump-on-signal and periodic dumps; on wedge sendSIGUSR1/SIGABRTper policy; if stacks show native wait, usegdb+py-bt; fix lock ordering across Python and extension locks. Pair with Distributed Deadlock Detection and Python Prefork Pitfalls.
Python Deadlock Debugging: production guidance
python
# ✅ boot path in gunicorn/uvicorn worker
import faulthandler
import signal
import sys
faulthandler.enable(file=sys.stderr, all_threads=True)
# Dump all threads on SIGUSR1 without killing the process
faulthandler.register(signal.SIGUSR1, file=sys.stderr, all_threads=True)
# Optional: periodic dump every 5 minutes while debugging a fleet
# faulthandler.dump_traceback_later(300, repeat=True, file=sys.stderr)
bash
# From the host / sidecar when readiness fails
kill -USR1 $(pgrep -f "uvicorn.*worker")
# stderr now has every Python thread stack
When Python stacks lie
If every thread is inPyEval_RestoreThread / extension pthread_mutex_lock, you need native frames.
bash
# ✅ gdb against the wedged PID (ECS exec / privileged debug sidecar)
gdb -p "$PID" -batch \
-ex "set pagination off" \
-ex "thread apply all bt" \
-ex "thread apply all py-bt" \
-ex "detach" -ex "quit"
python
# Reproduce classic extension + GIL hazard in staging
import threading
lock_a = threading.Lock()
lock_b = threading.Lock()
def t1():
with lock_a:
with lock_b:
pass
def t2():
with lock_b:
with lock_a: # ❌ inverted order → deadlock under race
pass
| Signal / tool | Shows | Kills process? |
|---|---|---|
SIGUSR1 + faulthandler |
Python stacks | No |
SIGABRT + faulthandler |
Python stacks + abort | Yes |
gdb py-bt |
Python + C | No (attach) |
py-spy dump |
Python samples | No |
Production playbook
- Confirm wedge: readiness fail, no RPS, CPU ~0, FDs stable.
kill -USR1→ collect stacks to CloudWatch / file.- If stuck in native code → ephemeral debug sidecar with matching symbols.
- Map lock graph; enforce global order; add timeouts (
lock.acquire(timeout=…)). - Add a canary that holds inverted locks in CI so the bug fails before prod.
Closing checklist
✅ Dos – ✅ Register faulthandler on worker boot – ✅ Document which signal dumps vs kills – ✅ Keep debug images with CPython debug symbols available – ✅ Enforce lock ordering docs in CODEOWNERS-owned modules – ✅ Prefer timeouts on cross-component locks ❌ Don’ts – ❌ Don’t ship without a dump signal in production – ❌ Don’t attach gdb to every task by default (audit + ephemeral only) – ❌ Don’t ignore wedges that “clear after bounce” – ❌ Don’t mixmultiprocessing locks with threads without a design
Related reading
- Distributed Deadlock Detection
- Python Prefork Pitfalls
- Node Heap Snapshots in Production
- Ephemeral Debug Sidecars
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- Css Animation Performance: Performance-Optimized Motion for Modern UIs
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
