Designing Architecture for Odoo Enterprise
/websocket/ must be explicitly routed to gevent workers and proxy_mode must be enabled.Why this structure is the safest
- Interactive HTTP for web users and APIs
- Cron / Batch for schedulers, heavy recomputes, large imports, and integrations
- Websocket / Gevent for long-lived connections (bus/livechat)
The Core Blueprint Layers
Layer 1 — The Edge
- WAF / CDN / DNS
- Load balancer pairs
- Reverse proxy (Nginx / HAProxy)
- HTTPS termination
Layer 2 — Odoo Application Pools
- Web UI users
- JSON-RPC / XML-RPC / REST APIs
- Lightweight form, list, kanban, and reporting reads
- Scheduled actions
- Massive data imports
- Mass recalculations
- Synchronized integrations and heavy jobs
- The
/websocket/routes - Livechat, bus, and persistent long-lived connections
/websocket/ necessitates routing to gevent workers, while ordinary HTTP requests should persist pointing strictly universally to standard web workers.Layer 3 — Shared Filestore
- A shared POSIX storage or consistent clustered filestore.
- Nginx
X-Accelconfigured to offload attachment streaming. - Static module assets served directly by Nginx.
Layer 4 — Database Tier
- 1 PostgreSQL Primary dedicated to all Odoo writes.
- 1 Standby HA primed for rapid failover.
- 1 Read Replica / Reporting Replica offloading BI, analytical audits, and huge queries.
- WAL archive + Continuous PITR backup.
Layer 5 — Connection Pooling
- Session pooling represents the safest default configuration for Odoo because it supports the entire spectrum of PostgreSQL features.
- Transaction pooling is drastically more aggressive but fragments session-based behaviors. Always validate it against your specific add-ons and query patterns.
Healthy Request Pipeline Topology
Browser / API Request
User / Kasir mengeklik tombol 'Confirm Order' di POS atau sebuah aplikasi third-party menembak API secara masif ke server Odoo.
Reverse Proxy & Load Balancer
Nginx menerima request. Mengurai HTTPS, dan mengecek rute. Jika itu minta file JPG/CSS, Nginx langsung kirim tanpa ganggu Odoo. Jika rute '/websocket/', ditendang ke Node Gevent. Jika normal, ditebar rata (Round Robin) ke kolam App Nodes.
Odoo Python App Pool
HTTP Worker dari Odoo menerima request. Mulai memvalidasi hak akses (Environment), menerjemahkan ORM create/write menjadi raw SQL query, dan merakit logika bisnis ERP.
PgBouncer (Connection Pooling)
Penyelamat nyawa Database! Menyerap 10,000 koneksi bar-bar dari ribuan Odoo App Nodes, lalu memasukkannya ke antrean rapi (Pool), dan mengumpankannya pelan-pelan murni hanya via 100-200 koneksi rapi ke PostgreSQL.
PostgreSQL Primary Database
Jantung eksekusi tunggal. Memproses query SQL, menembakkan trigger, menyimpan perubahan, lalu menyebarkan Write-Ahead Log (WAL) ke Standby Replica untuk backup HA dalam hitungan milidetik.
5 Immutable Design Principles
1) Isolate HTTP users, Cron, and Websockets
2) Database Write must remain a Single Source
3) Never let Odoo continuously serve Statics & Attachments
4) Built-in Observability
pg_stat_statements is mandatory for tracing the statistical planning and execution costs of all SQL queries. Activating csvlog or jsonlog enhances aggregation capabilities.5) Autovacuum is NEVER optional
ANALYZE when data mutates significantly. In massive datasets, autovacuum is not an accessory feature; it fundamentally prevents Table Bloat transaction collapse.How to Destroy Your ERP
All Traffic (Users + Cron + Websockets)
1 Monolithic Odoo Node
Direct Local Filestore & DB
Why this fails instantly at scale:
- No High Availability (Node death = Global Outage).
- Zero Workload Isolation (A heavy cron stalls frontend cashiers).
- Attachment streaming locks up active Python HTTP threads.
- Vertical scaling hits a severe ceiling swiftly.
Demystifying Node Separation (The Config Secret)
--workers dictates the number of HTTP workers, whereas --max-cron-threads dictates the worker count exclusively dedicated to scheduled actions.http_enable = False flag.The Ultimate 2-Node Recipe
👨💻App Node (Frontend)
odoo1.confworkers = 8
max_cron_threads = 0 # CRITICAL: 0 Crons
http_enable = True
proxy_mode = True
Serving active users. Fast, purely HTTP responding, isolated from heavy background tasks.
⚙️Cron Node (Backend)
odoo2.confworkers = 2
max_cron_threads = 4
http_enable = False # CRITICAL: Rejects HTTP
proxy_mode = True
Not registered in Nginx Load Balancer. Dedicated 100% to devouring heavy scheduled scripts.