Configuring uWSGI Emperor with the cheaper algorithm for dynamic worker scaling
Step‑by‑step guide to run multiple WSGI apps under uWSGI Emperor, enable the cheaper algorithm for dynamic worker scaling, and configure automatic vassal reload on file changes.
05 Sept 2026, 03:30 UTC

Desired outcome
Run multiple Python WSGI applications under a single uWSGI master (Emperor) that spawns vassals, scales workers dynamically using the cheaper algorithm, and reloads vassals automatically when source files change.
Prerequisites
- uWSGI version 2.0 or newer installed (via
pipor system package). - A Python virtualenv for each application.
- A directory for vassal configuration files, e.g.,
/etc/uwsgi/vassals, readable by the uWSGI process. - An unprivileged user and group (e.g.,
www-data) to drop privileges after startup. - Basic familiarity with editing INI files and using a terminal.
Procedure
1. Create vassal configuration files
For each application create a .ini file in the vassals directory. Below is an example for an app named myapp.
# /etc/uwsgi/vassals/myapp.ini
[uwsgi]
# Socket – adjust path or port as needed
socket = /run/uwsgi/myapp.sock
chmod-socket = 660
# WSGI entry point
module = myapp.wsgi:application
# Virtualenv location
virtualenv = /opt/myapp/venv
# Improve memory usage with lazy loading
lazy-apps = true
# Enable threads if your app uses them
enable-threads = true
# Cheaper algorithm for dynamic worker scaling
cheaper-algo = backlog2
cheaper-initial = 2 # workers at start
cheaper-min = 1 # minimum workers
cheaper-max = 10 # maximum workers
cheaper-step = 1 # add/remove this many workers per adjustment
# Automatic reload when source files change
# Option A: touch the .ini file to trigger reload
touch-reload = /etc/uwsgi/vassals/myapp.ini
# Option B: monitor specific source directories/files
# files-mon = /opt/myapp/src
# Logging
logto = /var/log/uwsgi/%n.log
Explanation of key directives:
cheaper-algo=backlog2selects the backlog‑based cheaper algorithm.cheaper-initial,cheaper-min,cheaper-maxandcheaper-stepcontrol the worker pool size.touch-reload(orfiles-mon) tells uWSGI to watch for changes and perform a graceful reload.
2. Start the Emperor
Run the Emperor as root, then drop to the unprivileged uid/gid. Execute the following command with root privileges (e.g., via sudo).
# Run as root
sudo uwsgi \
--emperor /etc/uwsgi/vassals \
--emperor-tyrant \
--uid www-data \
--gid www-data \
--daemonize /var/log/uwsgi-emperor.log
The --emperor-tyrant flag allows the Emperor to change the ownership of vassal sockets to the specified uid/gid.
3. Verify vassal spawning and worker scaling
After starting, check the Emperor log for vassal initialization:
[emperor] vassal myapp.ini is ready
[emperor] vassal myapp.ini has been spawned
Each vassal’s own log should show worker start/stop messages as the cheaper algorithm adjusts the pool.
4. Observe dynamic worker count
Use either uwsgitop (if installed) or the built‑in stats server.
To enable the stats server, add to the vassal .ini:
stats = 127.0.0.1:9191
Then, in a terminal:
# With uwsgitop
uwsgitop 127.0.0.1:9191
# Or curl the stats endpoint (JSON output)
curl http://127.0.0.1:9191
Look for the workers field; it should rise and fall as load changes.
5. Test automatic reload
Make a change to a watched source file (or touch the vassal .ini). The Emperor log should contain:
[emperor] vassal myapp.ini has been lost
[emperor] vassal myapp.ini has been spawned
Requests should continue without HTTP 5xx errors during the graceful reload.
Expected checks
- Emperor log (
/var/log/uwsgi-emperor.log) shows vassal spawning and reload events. - Vassal logs reflect worker start/stop according to cheaper‑algorithm settings.
- Stats endpoint or
uwsgitopreports varying worker numbers under load. - After a file change, a reload log appears and subsequent requests succeed.
Recovery options (rollback)
Starting the Emperor and vassals changes system state (processes, sockets, log files). To stop:
- Find the Emperor process ID:
ps -ef | grep uwsgi. - Send a SIGTERM:
sudo kill <emperor_pid>. - Verify that all vassal processes have exited (
pgrep -u www-data uwsgireturns nothing). - If needed, remove the vassal
.inifiles or move them elsewhere to prevent respawn on restart.
Restarting the Emperor with the same command will restore the previous configuration.
Limitations and practical verification
The cheaper algorithm requires tuning: setting cheaper-min too low may cause worker starvation under sudden traffic spikes, while setting cheaper-max too high wastes memory. Start with modest values (e.g., 1‑2‑10‑1) and adjust while monitoring the stats server under realistic load.
To verify that the algorithm is active, compare worker count before and after generating load (e.g., with hey -z 30s http://your‑app/). An increase in the workers field indicates the algorithm is scaling up; a decrease after load stops indicates scaling down.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.