"""Shared gunicorn config — the BOUNDED, THREADED worker pool that replaces every hand-rolled
single-threaded http.server (operator: "no single-threaded HTTP server anywhere"; the #250 lesson).

⚠️ gunicorn's DEFAULT worker_class is "sync" — SINGLE-THREADED PER WORKER: each process serves
exactly ONE request at a time, so a slow handler blocks its whole worker. That quietly re-introduces
the very thing we are eliminating. So this base DEFAULTS to **gthread — the ThreadedWorker**: every
worker process runs `threads` threads and serves them concurrently, which is exactly right for our
I/O-bound handlers (DB + S3 + onward-HTTP all release the GIL). Effective concurrency = workers ×
threads. A rare CPU-bound service can opt back to processes with GUNICORN_WORKER_CLASS=sync.

One place tunes the whole fleet; every knob is an env override, so concurrency changes from the
unit/compose with NO image rebuild.

    exec gunicorn -c python:andrea_svc_web.gunicorn_conf myservice.wsgi:application
"""
import os

bind = os.environ.get("SVC_BIND", "0.0.0.0:8000")

# ── the ThreadedWorker (operator 2026-07-19) ────────────────────────────────────────────────────
worker_class = os.environ.get("GUNICORN_WORKER_CLASS", "gthread")     # threaded, NOT the sync default
workers = int(os.environ.get("GUNICORN_WORKERS", "2"))                # processes (memory-light w/ threads)
threads = int(os.environ.get("GUNICORN_THREADS", "8"))               # threads PER worker (the gthread knob)

timeout = int(os.environ.get("GUNICORN_TIMEOUT", "30"))
graceful_timeout = int(os.environ.get("GUNICORN_GRACEFUL_TIMEOUT", "30"))
keepalive = int(os.environ.get("GUNICORN_KEEPALIVE", "5"))
# worker_connections caps in-flight requests for the ASYNC workers (gevent/eventlet) only; gthread's
# ceiling is `threads`. Kept for a service that opts into an async worker class.
worker_connections = int(os.environ.get("GUNICORN_WORKER_CONNECTIONS", "256"))
accesslog = os.environ.get("GUNICORN_ACCESSLOG", "-")
errorlog = os.environ.get("GUNICORN_ERRORLOG", "-")
