Ir al contenido

Odoo 16–19 con PgBouncer: arquitectura recomendada, compatibilidades y "gotchas" reales

4 de diciembre de 2025 por
Odoo 16–19 con PgBouncer: arquitectura recomendada, compatibilidades y "gotchas" reales
John Wolf
| Todavía no hay comentarios

PgBouncer es una de las mejoras con mejor ROI cuando escalas Odoo: menos conexiones reales a PostgreSQL, menos overhead, más estabilidad en picos. Pero para que funcione fino en Odoo 16, 17, 18 y 19, hay dos verdades importantes:

  1. Odoo en producción necesita reverse proxy + WebSocket bien encaminado. Odoo+2Odoo+2

  2. PgBouncer en pool_mode=transaction es ideal para web… pero rompe ciertas features de sesión (y ahí vive el 90% de los sustos). PgBouncer+1

Vamos al grano.


1) Lo que NO cambió (mucho) entre Odoo 16 → 19

En los docs oficiales de Odoo (16, 17, 18 y 19) se repite el mismo patrón de producción:

  • modo multi-proceso activado con --workers

  • cálculo recomendado de workers: (#CPU * 2) + 1

  • un worker dedicado para LiveChat/WebSocket en --gevent-port

  • y el proxy debe enrutar /websocket/ hacia ese puerto (y activar --proxy-mode) Odoo+3Odoo+3Odoo+3

En Odoo 19 incluso viene un ejemplo de Nginx donde location /websocket va al upstream de 8072 (gevent). Odoo


2) Arquitectura recomendada (simple, escalable y “anti-incendios”)

Topología típica (1 DB, 1 usuario DB):

Nginx/HAProxy (443)

→ Odoo HTTP workers 8069

→ Odoo WebSocket (LiveChat) 8072 (gevent_port) Odoo+1

→ PgBouncer 6432

→ PostgreSQL 5432


Por qué esta arquitectura funciona

  • El proxy separa tráfico “normal” (HTTP) del tráfico “long-lived” (WebSocket). Odoo lo recomienda explícitamente: /websocket/ debe ir al worker LiveChat en --gevent-port. Odoo+1

  • PgBouncer absorbe el “ruido” de conexiones (sobre todo con muchos workers) y limita el número de backends reales a Postgres.


3) Config mínima (copiar/pegar) para Odoo 16–19

Odoo (odoo.conf)

[options]
proxy_mode = True

workers = 8
max_cron_threads = 1

; WebSocket / LiveChat
gevent_port = 8072
longpolling_port = False
  • La guía oficial indica que en multi-processing hay un LiveChat worker en --gevent-port y que /websocket/ debe redirigirse ahí. Odoo+2Odoo+2

  • longpolling_port es un alias/deprecado y en la práctica se suele poner en False para evitar warnings. Odoo


Nginx (idea base)

  • /websocket/ → 8072

  • / → 8069

Esto está alineado con el ejemplo oficial (Odoo 19) que redirige /websocket al upstream del gevent port. Odoo


4) PgBouncer para Odoo: el modo correcto (y el límite real)

Regla general

Para Odoo web: pool_mode = transaction.

PgBouncer define transaction pooling así: “una conexión server se asigna al cliente solo durante la transacción, y luego vuelve al pool”. GitHub


Ajustes base (PgBouncer)

  • pool_mode = transaction

  • default_pool_size (tu límite de concurrencia real por (db,user))

  • reserve_pool_size (picos cortos sin sobredimensionar)

  • max_client_conn (capacidad de entradas)

Esto te da un comportamiento predecible: si hay saturación, la ves como cola en PgBouncer (no como “Postgres murió”).


5) El “gotcha” #1: LISTEN/NOTIFY + transaction pooling

Aquí es donde mucha gente se quema.

  • PgBouncer documenta que transaction pooling rompe expectativas de sesión y solo funciona si la app “coopera” (no usa features no compatibles). PgBouncer+1

  • En particular, LISTEN es un ejemplo típico de feature de sesión que no encaja bien en transaction pooling (porque necesita mantener la misma conexión).

  • La OCA lo resume directamente para Odoo: las features de longpolling/tiempo real se apoyan en LISTEN/NOTIFY; NOTIFY pasa, pero LISTEN no en ese modo, porque LISTEN necesita mantener la conexión server abierta. Odoo Community


Soluciones que sí funcionan (elige una)

Opción A (la más práctica): “bypass” solo para la conexión que escucha

  • Mantienes Odoo → PgBouncer (transaction) para el 99% del tráfico

  • y dejas una conexión directa a Postgres para el “listener” (OCA propone ese enfoque). Odoo Community

Opción B: pool dedicado en pool_mode=session para lo que requiera sesión

  • Todo lo normal sigue en transaction

  • Pero lo “sesión-dependiente” va por session pooling (menos eficiente, pero compatible)

Resultado: estabilidad + features real-time sin sacrificar el pooling donde más rinde.


6) El “gotcha” #2: WebSocket mal encaminado (parece “bug”, es proxy)

En Odoo 16–19, si /websocket/ no llega al gevent_port, aparecen síntomas raros:

  • chat/Discuss sin “tiempo real”

  • notificaciones que no llegan

  • errores 400 en /websocket

La doc lo deja claro: necesitas proxy delante y redirigir /websocket/ al worker LiveChat, además de --proxy-mode. Odoo+2Odoo+2


7) Dimensionamiento rápido (que se sostiene en producción)

Los docs de Odoo (17–19, y también 16) dan reglas prácticas que puedes usar como base:

  • workers: (#CPU * 2) + 1

  • 1 worker ≈ 6 usuarios concurrentes (regla orientativa)

  • estimación de RAM por worker “heavy/light” Odoo+3Odoo+3Odoo+3

Con eso defines workers, y luego dimensionas PgBouncer para controlar el backend real.


8) Seguridad mínima: HTTPS sí o sí

Odoo advierte que transmite credenciales en claro si no hay HTTPS, y recomienda desplegar SSL termination en el proxy. Odoo+1

En términos de resultado: sin HTTPS no hay “producción seria”, aunque la app “funcione”.


Cierre

Para Odoo 16–19, PgBouncer es un upgrade muy rentable si lo despliegas así:

  • Proxy bien hecho: /websocket/ → gevent_port

  • PgBouncer en transaction para el grueso del tráfico

  • Y una estrategia clara para features de sesión (LISTEN), ya sea bypass puntual o pool en session


Siguiente capítulo ->

Odoo 16–19 con PgBouncer: arquitectura recomendada, compatibilidades y "gotchas" reales
John Wolf 4 de diciembre de 2025
Compartir
Etiquetas
Archivo
Iniciar sesión dejar un comentario