19 views
Gunicorn/multiprocessing prefork copies the parent address space. That includes open DB sockets, SSL sessions, boto3 clients, logging listeners, and PRNG state. Two workers then fight over one TCP connection or emit identical “random” tokens. The fix is ritualized: close or reset everything that is not fork-safe in post_fork (or never create it before fork).
⚡ TL;DR: Create connection pools after fork; re-seedrandom/secrets/NumPy RNGs in each worker; close inherited sockets; restartQueueListenerthreads. SnapStart and Lambda freeze/restore have the same class of bugs—see Lambda SnapStart for Python: Pitfalls Beyond the Java Marketing. Worker model context: Python asyncio vs Threading vs Multiprocessing.
Python Prefork Pitfalls: production guidance
python
# ❌ Created in master before fork
import boto3
from sqlalchemy import create_engine
engine = create_engine(os.environ["DATABASE_URL"], pool_size=5)
s3 = boto3.client("s3")
# workers inherit same pool connections → protocol chaos
post_fork: dispose and rebuild
python
# gunicorn_conf.py
import os, random, logging
def post_fork(server, worker):
# RNGs
random.seed(int.from_bytes(os.urandom(16), "big"))
try:
import numpy as np
np.random.seed(None)
except ImportError:
pass
# SQLAlchemy
from app.db import engine
engine.dispose(close=True) # ✅ drop inherited conns; pool recreates lazily
# HTTP / AWS clients: rebuild
from app import clients
clients.reset()
# Logging listeners (threads do not survive fork cleanly)
from app.logging_setup import configure_async_logging
configure_async_logging()
logging.getLogger(__name__).info("worker_booted pid=%s", worker.pid)
python
# app/clients.py
import boto3
_s3 = None
def reset():
global _s3
_s3 = boto3.client("s3")
def s3():
if _s3 is None:
reset()
return _s3
Inherited sockets and listen FDs
The master should own the listen socket; workers accept after fork—that part is fine. Client connections opened during master preload are not. Also watch:- Redis/
hiredisconnections - gRPC channels
- OpenTelemetry exporters / background BatchSpanProcessor threads
multiprocessing.Queuefeeder threads
python
# ✅ Lazy init pattern
class Pool:
def __init__(self):
self._redis = None
def redis(self):
if self._redis is None:
import redis
self._redis = redis.Redis.from_url(os.environ["REDIS_URL"])
return self._redis
ECS/K8s vs Gunicorn
On ECS Fargate you often run one process per task (no prefork)—simpler. If you still prefork inside the task for CPU-bound workers, apply the samepost_fork checklist. Graceful shutdown must drain the worker before the master exits—mirror Node drain patterns in Graceful Shutdown for Node when available, or your orchestrator’s preStop hook.
Closing checklist
✅ Dos – ✅engine.dispose() / close pools in post_fork
– ✅ Re-seed all RNGs per worker
– ✅ Rebuild SDK clients and OTEL processors after fork
– ✅ Prefer lazy init for sockets created on first use
– ✅ Log worker pid on boot for correlation
❌ Don’ts
– ❌ Don’t open DB/Redis connections in the master preload without dispose
– ❌ Don’t assume threads survive fork
– ❌ Don’t share SSL sessions across workers
– ❌ Don’t generate idempotency keys with a forked PRNG
– ❌ Don’t ignore silent duplicate side effects after deploy
Related reading
- Lambda SnapStart for Python: Pitfalls Beyond the Java Marketing
- Python asyncio vs Threading vs Multiprocessing
- Lambda Warm Pools: Low-Latency Backends for Coding Agent Tools
- Human-in-the-Loop Gates: Dual Control for Prod-Touching Agent Tools
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.

Pingback: Python Deadlock Debugging: faulthandler Plus gdb for Wedged Workers - CheatCoders
Pingback: Python Shared Memory Multiprocessing: Batch Features Without Pickle Blowups - CheatCoders