Volver a la wiki

CONN_MAX_AGE=0 con Daphne ASGI

ADR — CONN_MAX_AGE=0 con Daphne ASGI

Contexto

CreaRack Pro usa Daphne como servidor ASGI. En config/settings/base.py, "daphne" primera entrada de INSTALLED_APPS (requerimiento Django Channels para habilitar HTTP2/WebSocket desde arranque). La app mantiene WebSocket persistentes para Sentinel de red y terminales interactivas; bajo carga moderada puede haber decenas de hilos Daphne activos simultáneamente.

CONN_MAX_AGE no definido en base.py; se delega a entornos (production.py, development.py). En 4 ocasiones distintas un valor CONN_MAX_AGE > 0 llegó a producción, provocando saturación PostgreSQL y pérdida de disponibilidad.

Problema

Daphne gestiona cada conexión HTTP/WS en un hilo propio. Con CONN_MAX_AGE > 0, Django mantiene la conexión BD abierta y ociosa durante esa ventana. El Sentinel de red genera ráfagas de reconexiones en eventos; en picos, 200+ conexiones idle se acumulan simultáneamente y agotan max_connections de PostgreSQL. Resultado: OperationalError: too many connections, app inaccesible.

Patrón repetido en: 327af62, revert c1ede18→4c9d37b, revert bc2e1d8→a6f5392, más un cuarto incidente no consolidado. Valor >0 siempre introducido como efecto colateral de operaciones pgbouncer, no intencional.

Opciones consideradas

CONN_MAX_AGE=60 — reutiliza conexiones 60s. Mejora latencia media pero incompatible con modelo de hilos Daphne; produce el problema descrito.

CONN_MAX_AGE=0 — Django abre/cierra conexión en cada request. Overhead <1ms en red Docker interna. Elimina riesgo de acumulación. Sin infraestructura adicional.

Connection pooling externo (PgBouncer transaction mode) — delega pooling fuera de Django; compatible con ASGI porque pool vive en proceso independiente. Combina con CONN_MAX_AGE=0: Django no reutiliza, PgBouncer recicla del pool transparentemente. Opción adoptada a largo plazo.

Decisión

CONN_MAX_AGE=0 en todos los entornos con Daphne activo, combinado con PgBouncer en transaction mode como capa de pooling externo. Django nunca mantiene conexiones persistentes; PgBouncer gestiona pool independientemente del número de hilos ASGI.

Regla operativa: si se añade, elimina o reconfigura PgBouncer, CONN_MAX_AGE=0 debe preservarse explícitamente. Los dos valores no son interdependientes y no deben tocarse en el mismo commit sin revisión deliberada.

Consecuencias

Status

Accepted. Revertido incorrectamente 4 veces antes de consolidar. Cualquier PR que modifique CONN_MAX_AGE en producción debe referenciar este ADR y justificar desviación.

Véase también

Subir