Enable Dark Mode!
how-to-optimize-worker-usage-in-odoo-19.jpg
By: Sayed Mahir Abdulla KK

How to Optimize Worker Usage in Odoo 19

Technical Odoo 19 Odoo Enterprises Odoo Community

When you are experiencing lagging in your Odoo installation, buying additional memory will rarely be the solution. Instead, it would help to check whether you have set the number of workers appropriately – too many, too few, or an incorrect ratio between HTTP and cron workers.

Odoo 19 works in a multi-process environment. For each incoming request, a new process spawns, meaning that when there are no free workers, other processes are left waiting. Here is a great blog post about handling multiple workers.

The formula Odoo actually recommends

Odoo's own documentation gives a starting formula: (CPU cores × 2) + 1 worker processes for HTTP, with one or two dedicated cron workers on top.

Example:

Workers - 9 - (4×2)+1
Max_cron_threads - 2 - dedicated schedulers
Limit_memory_hard - 2684354560 - 2.5 GB per worker
Limit_time_cpu - 60 - seconds CPU per req

These go in your odoo.conf:

# /etc/odoo/odoo.conf
workers = 9
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_cpu = 60
limit_time_real = 120
limit_request = 8192

Note: Total worker memory must fit in RAM. 9 workers × 2.5 GB = ~22.5 GB. If your server only has 16 GB, you'll thrash. Either reduce the number of workers or reduce the per-worker memory limit.

Why cron workers deserve their own tuning

These cron workers perform scheduled tasks such as invoicing, email queueing, and inventory management. They do not process HTTP requests; including them among the normal workers is a widespread error.

If max_cron_threads is 0, Odoo will not schedule any jobs in the multiprocessing environment at all. If it is too large, an intensive batch task might consume all CPU resources allocated to your HTTP workers.

In almost all cases, 1 or 2 cron workers suffice. The only exception would be when performing intense batch jobs on a regular basis in business hours.

Odoo 19's new worker improvements

In Odoo 19, there is enhanced worker recycling. The earlier versions would retain zombie workers even after memory limit violations. This problem has been fixed in Odoo 19, where the worker management process becomes more aggressive in harvesting zombies and creating new workers, thereby keeping the configured worker count closer to the active worker count.

Additionally, there are better logs for the state of the worker. When you use the command --log-level=debug, the logs will now show when workers were recycled because of memory limits. This helps you find silent out-of-memory errors that did not appear until you encountered slow server performance in earlier versions.

Diagnosis

The fastest check: look at worker logs during peak load. In /var/log/odoo/odoo.log, you want to see something like:

# Healthy — workers cycling normally
WorkerHTTP (4) lives on pid=31204
WorkerHTTP (5) lives on pid=31205
# Problem — worker killed on memory
Worker (4) max memory reached, killing (pid=31204)

Memory death happens when your limit_memory_hard is too small relative to the jobs that are being done. Or you may have a memory leak somewhere. Fewer workers will sometimes solve the problem (because fewer workers have the same amount of RAM available to them).

If you are not getting the "lives on" messages, you are running in thread mode instead of multiprocess mode. This is OK for development, but it does not allow any parallel execution or security among requests. Do not use this mode in production.

Nginx in front of Odoo

One thing that genuinely helps more than tuning worker count is to put Nginx in front with proper timeouts. Without it, a slow client connection holds an Odoo worker open for the entire transfer. With Nginx as a reverse proxy, the worker finishes and Nginx handles the slow client.

# nginx.conf snippet
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
proxy_buffer_size 64k;
proxy_buffers 8 64k;

Match proxy_read_timeout to your limit_time_real in Odoo config. If Nginx gives up before Odoo does, users get 502 errors on long operations. If Odoo gives up first, Nginx gets an empty response. Neither is great.

Mistakes to be noted:

  1. Setting workers to a very high number like 30 or 40 doesn't improve throughput on an 8-core machine. You'll get more context switching, more memory pressure, and roughly the same requests-per-second. Workers waiting on the CPU don't help anyone.
  2. Setting limit_time_real very high (like 3600 seconds) to "allow long operations" usually just means slow queries hold workers hostage. The real fix there is query optimization, not patience.

Worker tuning isn't a one-time task. It shifts as your dataset grows, as you add modules, and as your user count changes. Schedule a check every few months, not just when something breaks.

To read more about How to Set Up Workers in Odoo 19 for Better Performance, refer to our blog, How to Set Up Workers in Odoo 19 for Better Performance.


Frequently Asked Questions

How do I know the right number of workers for my server?

Start with (CPU cores × 2) + 1 for HTTP workers, plus 1–2 cron workers on top. For a 4-core server that's 9 HTTP workers and 2 cron workers. Before applying this, check that total worker count × limit_memory_hard fits within your available RAM; if it doesn't, reduce one or both. On shared VPS hosting where you don't have guaranteed CPU, cut the formula in half and scale up from there based on actual log behavior.

What happens if max_cron_threads is set to 0?

Odoo stops running scheduled jobs entirely in multiprocess mode. That means no automatic invoicing, no email queue processing, no inventory reordering rules, no scheduled reports — nothing. It's a silent failure; the system won't error out, jobs just won't run. Set it to at least 1. For most deployments, 1–2 is enough unless you have heavy batch operations running during business hours.

Logs show frequent "max memory reached, killing" messages. What should I do?

Two things to check. First, your limit_memory_hard may simply be too low for the operations your workers are running — raising it helps if you have RAM headroom. Second, if raising the limit doesn't stop the kills, you likely have a memory leak in a custom module or a query that builds large recordsets. In that case, reducing worker count gives each remaining worker more breathing room while you investigate. Don't increase workers as a fix — it makes memory pressure worse.

Do I need Nginx if I already have enough workers configured?

Yes, for a different reason. Worker count controls parallelism Nginx controls connection handling. Without Nginx, a slow client (poor mobile connection, large file download) keeps an Odoo worker tied up for the entire transfer duration. Nginx as a reverse proxy buffers the response, frees the worker immediately, and handles the slow client itself. This alone can reduce effective worker load significantly under real-world traffic. Also make sure proxy_read_timeout in Nginx matches limit_time_real in Odoo a mismatch causes either 502 errors or hanging responses.

Is it safe to run Odoo in thread mode (no workers) in production?

No. Thread mode is single-process all requests share one Python process with no parallelism and no isolation between requests. A single slow query or memory spike affects every user simultaneously. It's fine for local development, but in production it becomes a bottleneck almost immediately under real load. If your logs show no "WorkerHTTP lives on pid=..." lines at all, you're in thread mode. Add workers = N to odoo.conf to switch to multiprocess mode.

If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message