En producción, los problemas “no avisan” con mensajes bonitos. Suelen aparecer como: lentitud intermitente, picos de 500, timeouts, o “solo a ciertas horas”. En este post recopilo errores muy comunes (y reales) en stacks Odoo + PgBouncer, con el patrón:
Síntoma → Causa raíz → Cómo se resolvió → Cómo evitar que vuelva.
1) PoolError: The Connection Pool Is Full (Odoo) en longpolling / picos
Síntoma
Errores 500 en endpoints tipo /longpolling/poll o en momentos de carga.
Traceback con: psycopg2.pool.PoolError: The Connection Pool Is Full. Odoo
Causa raíz (lo típico)
db_maxconn demasiado bajo para la concurrencia real (workers + crons + longpolling).
O bien picos donde muchas requests intentan abrir cursor al mismo tiempo.
A veces se ve “aunque el cálculo teórico daba” (porque el tráfico real y el longpolling hacen que el peor caso ocurra más seguido). Odoo+1
Cómo se resolvió
Subir db_maxconn moderadamente (sin hacerlo gigante).
Revisar workers y especialmente max_cron_threads (crons paralelos + longpolling es combo explosivo).
Si había PgBouncer, asegurarse de que max_client_conn no estuviera limitando “por arriba”.
Cómo evitar que vuelva
Instrumentar picos: si suben los 500, mirar qué hora y qué cron coincide.
En PgBouncer, vigilar cl_waiting (si ya hay cola, Odoo tenderá a reintentar y el pool interno sufre).
2) “Todo anda, pero tiempo real / chat / notificaciones no funcionan” (WebSocket mal ruteado)
Síntoma
Odoo carga, pero Discuss/Livechat/notificaciones en tiempo real se sienten “muertas”.
A veces ves errores en /websocket/ o simplemente no hay updates.
Causa raíz
Reverse proxy (Nginx/Apache) no está redirigiendo /websocket/ al puerto gevent (gevent_port, típico 8072).
En multi-worker esto es un clásico: el HTTP va a 8069, pero WebSocket debe ir separado. Odoo+2Full Stack Web Dev & Designer Expert+2
Cómo se resolvió
Arreglar proxy:
/ → upstream Odoo HTTP (8069)
/websocket/ → upstream gevent (8072)
Confirmar que Odoo tiene gevent_port configurado.
Cómo evitar que vuelva
Checklist de deploy: “¿/websocket está ruteando al upstream correcto?”
Healthcheck específico a /websocket/ (si tu stack lo permite) además del /web.
3) “Con PgBouncer en transaction pooling, el bus/NOTIFY/LISTEN se rompe”
Síntoma
“Tiempo real” inconsistente: a veces llega, a veces no.
Notificaciones que dependen de LISTEN/NOTIFY se comportan raro.
Causa raíz
LISTEN/NOTIFY no funciona bien con pool_mode=transaction, porque transaction pooling rompe expectativas de sesión: el cliente no conserva la misma conexión server. Esto se discute abiertamente en el ecosistema PgBouncer. GitHub+2PgBouncer+2
Cómo se resolvió (patrones que sí funcionan)
Mantener PgBouncer en transaction para el 95–99% del tráfico (ORM normal).
Para el componente que necesita sesión persistente:
bypass directo a PostgreSQL, o
PgBouncer aparte en pool_mode=session solo para ese caso.
Cómo evitar que vuelva
Documentar internamente: “transaction pooling ≠ features de sesión”.
Si tu Odoo depende de mecanismos real-time, planear esa excepción desde el inicio.
4) “La app se pone lenta en oleadas”: cl_waiting sube en PgBouncer
Síntoma
Usuarios se quejan de lentitud “por rachas”.
No siempre hay error; solo tarda.
Señal clave
En PgBouncer, SHOW POOLS; y ves:
cl_waiting creciendo (clientes esperando conexión server).
GitLab lo resume perfecto: cl_waiting indica que clientes intentan ejecutar una transacción pero PgBouncer no pudo asignarles una conexión server de inmediato; si crece, suele ser porque las conexiones están siendo “hogged” (transacciones largas) o el pool quedó chico. Runbooks
Causa raíz típica
Un cron pesado o import masivo abrió transacciones largas y “secuestró” conexiones server.
O simplemente default_pool_size demasiado bajo para el pico real.
Cómo se resolvió
Primero identificar si hay transacciones largas/locks (Postgres).
Si era pico legítimo y Postgres estaba cómodo: subir default_pool_size y/o usar reserve_pool_size.
Si era transacción larga: reescribir el job a batching (lotes más pequeños) para liberar conexiones más rápido.
Cómo evitar que vuelva
Alerta temprana: cl_waiting > 0 sostenido.
Alertar también por transacciones > X segundos (Postgres), porque eso predice cl_waiting.
5) “PgBouncer no reutiliza conexiones / comportamiento raro con statements”: prepared statements + transaction pooling
Síntoma
Conexiones que parecen “raras”: más churn, errores o comportamiento no esperado con ciertos drivers.
A veces se ve como “no reusa, crea nuevas”, o errores difíciles de reproducir.
Causa raíz
PgBouncer en pool_mode=transaction no soporta bien ciertas expectativas de sesión, y eso incluye casos con prepared statements, especialmente con algunos clientes/drivers. Esto se menciona frecuentemente en troubleshooting de producción. Stack Overflow+1
Cómo se resolvió
Si el driver dependía fuertemente de prepared statements “a nivel sesión”, se evaluó:
desactivarlos del lado del cliente (si aplica), o
usar pool_mode=session para ese servicio específico (no para todo Odoo), o
separar workloads (servicio A por transaction, servicio B por session).
Cómo evitar que vuelva
No mezclar “todo por session” por miedo: session pooling es más caro.
Pero tampoco forzar transaction pooling donde el cliente no coopera (la propia doc de PgBouncer lo advierte). PgBouncer+1
6) El patrón que más se repite: “arreglamos con métricas, no con fe”
Cuando un incidente aparece, hay un orden que casi siempre ahorra tiempo:
PgBouncer → SHOW POOLS;
¿hay cl_waiting?
Si hay cola: ¿es por pool chico o por “conexiones secuestradas”?
GitLab recomienda investigar long-running queries/transactions si cl_waiting sube. Runbooks
Postgres → pg_stat_activity
¿hay transacciones largas o locks?
Recién después ajustar:
default_pool_size / reserve_pool_size (si es demanda legítima)
crons/batching (si es transacción larga)
proxy/websocket (si es real-time)
Cierre
La mayoría de “errores raros” en Odoo + PgBouncer no son raros: son dos o tres gotchas repetidos:
pool interno de Odoo insuficiente para el pico real,
websocket mal ruteado,
y transaction pooling usado en features que necesitan sesión,
más crons con transacciones largas secuestrando conexiones.