# Standard deployment on a single machine
pool:
workers: 4 # Number of Python processes
max_in_flight: 10 # Max concurrent requests across the pool
max_in_flight_per_worker: 1 # Max in-flight requests per worker
health_interval: 30s # Health check frequency
python:
executable: python3
worker_script: /app/worker.py
env:
PYTHONUNBUFFERED: "1"
socket:
dir: /tmp
prefix: pyproc
permissions: 0600Place Go app and Python workers in the same pod for UDS communication:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
volumes:
- name: pyproc-sockets
emptyDir: {}
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: pyproc-sockets
mountPath: /var/run/pyproc
env:
- name: PYPROC_SOCKET_DIR
value: /var/run/pyproc
- name: PYPROC_POOL_WORKERS
value: "4"version: '3.8'
services:
app:
build: .
volumes:
- sockets:/var/run/pyproc
environment:
PYPROC_SOCKET_DIR: /var/run/pyproc
PYPROC_POOL_WORKERS: 4
volumes:
sockets:
driver: local- One Go process manages one or more Python workers
- Each worker listens on a dedicated Unix domain socket
- Workers are isolated - crash of one doesn't affect others
- Automatic restart on worker failure (configurable)
cfg := pyproc.WorkerConfig{
ID: "worker-1",
SocketPath: "/tmp/pyproc.sock",
PythonExec: "python3",
WorkerScript: "worker.py",
StartTimeout: 30 * time.Second,
Env: map[string]string{
"PYTHONUNBUFFERED": "1",
"MODEL_PATH": "/models/latest",
},
}poolCfg := pyproc.PoolConfig{
Workers: 4, // Number of workers
MaxInFlight: 10, // Global concurrency across the pool
MaxInFlightPerWorker: 1, // Per-worker in-flight cap
HealthInterval: 30 * time.Second, // Health check frequency
Restart: pyproc.RestartConfig{
MaxAttempts: 5,
InitialBackoff: 1 * time.Second,
MaxBackoff: 30 * time.Second,
Multiplier: 2.0,
},
}Python workers automatically expose a health endpoint:
# Automatically registered by pyproc_worker
def health(req):
return {
"status": "healthy",
"pid": os.getpid(),
"uptime": time.time() - start_time,
"requests_handled": request_count
}Export Prometheus metrics from Go:
// Recommended metrics endpoint
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":9090", nil)Key metrics to track:
pyproc_worker_requests_total- Total requests per workerpyproc_worker_request_duration_seconds- Request latencypyproc_worker_errors_total- Error count by typepyproc_worker_restarts_total- Worker restart countpyproc_pool_inflight_requests- Current in-flight requests
Structured logging with trace IDs:
logger := pyproc.NewLogger(pyproc.LoggingConfig{
Level: "info",
Format: "json",
TraceEnabled: true,
})Log aggregation recommendations:
- Use structured JSON logging
- Include trace IDs for request correlation
- Ship logs to centralized system (ELK, Datadog, etc.)
- Go application starts
- Worker pool initialized
- Python workers spawned
- Socket connections established
- Health checks begin
- Ready to serve requests
// Handle shutdown signals
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := pool.Shutdown(ctx); err != nil {
log.Printf("Shutdown error: %v", err)
}Configure automatic restart with exponential backoff:
restart:
max_attempts: 5
initial_backoff: 1s
max_backoff: 30s
multiplier: 2.0- Python processes can consume significant memory
- Monitor RSS (Resident Set Size) per worker
- Set memory limits in container deployments
- Consider worker recycling after N requests
# Kubernetes resource limits
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"Ensure sufficient file descriptors:
# Check current limit
ulimit -n
# Increase limit (add to systemd service or container)
ulimit -n 65536# Optimal worker count formula
workers = min(
cpu_cores * 2, # CPU-bound workloads
cpu_cores * 4 # I/O-bound workloads
)// Tune socket buffers for large payloads
conn.SetReadBuffer(1024 * 1024) // 1MB
conn.SetWriteBuffer(1024 * 1024) // 1MB// Match MaxInFlight to expected concurrency
MaxInFlight: runtime.NumCPU() * 2
// Keep per-worker at 1 unless the Python worker can process concurrent requests
MaxInFlightPerWorker: 1-
Worker won't start
- Check Python path and dependencies
- Verify socket permissions
- Review worker script syntax
-
High latency
- Monitor worker CPU usage
- Check for GIL contention
- Increase worker count
-
Connection refused
- Verify socket path exists
- Check filesystem permissions
- Ensure worker is running
-
Memory leaks
- Monitor Python process memory
- Implement worker recycling
- Profile Python code
Enable debug logging:
logger := pyproc.NewLogger(pyproc.LoggingConfig{
Level: "debug",
})Check worker health status:
# Manual health check
echo '{"id":1,"method":"health","body":{}}' | \
nc -U /tmp/pyproc.sock- Run workers with least privilege user
- Set restrictive socket permissions (0600)
- Validate input in Python functions
- Use separate Python virtual environments
- Regular dependency updates
- Monitor for anomalous behavior
- Configure appropriate worker count
- Set up health checks and monitoring
- Implement graceful shutdown
- Configure restart policies
- Set resource limits
- Enable structured logging
- Set up metrics collection
- Test failure scenarios
- Document worker dependencies
- Create runbooks for common issues