Summary

Python server used for serving Django web requests at ICTC Solution Delivery

Commands

  1. Restart
service uwsgi-emperor status
service uwsgi-emperor restart

Installation

Emperor

- name: Install uWSGI emperor
  apt: name=uwsgi-emperor state=present

- name: Configure uWSGI emperor
  template:
    src: emperor.ini.j2
    dest: /etc/uwsgi-emperor/emperor.ini
    owner: root
    group: root
    mode: 0644
  notify: Restart uWSGI Emperor

- name: Create log directory
  file:
    path: /var/log/uwsgi/vassals
    state: directory
    owner: root
    group: root
  notify: Restart uWSGI Emperor

- name: Enable app server configuration (uWSGI emperor)
  template:
    src: uwsgi.ini.j2
    dest: "/etc/uwsgi-emperor/vassals/{{ uwsgi_app_name }}.ini"
    owner: root
    group: root
    mode: 0644
  notify: Restart application vassal

- name: Configure logrotate for uwsgi-emperor vassal
  template:
    src: logrotate-emperor-vassals.j2
    dest: /etc/logrotate.d/uwsgi-emperor-vassals
    owner: root
    group: root
    mode: 0644

uwsgi

  ---
##########################
#  Remove uWSGI Emperor
##########################

# Remove configuration files before purging package to allow apt to delete all
# configuration directories
- name: Remove uWSGI Emperor configuration
  file:
    path: "{{ item }}"
    state: absent
  loop:
    - /etc/uwsgi-emperor/emperor.ini
    - /etc/uwsgi-emperor/vassals

- name: Uninstall uWSGI emperor
  apt: name=uwsgi-emperor state=absent purge=yes

#########################################
#  Install and configure uWSGI
#########################################

- name: Install uWSGI
  apt: name=uwsgi state=present

- name: Configure uWSGI
  template:
    src: uwsgi.ini.j2
    dest: "/etc/uwsgi/apps-available/{{ uwsgi_app_name }}.ini"
    owner: root
    group: root
    mode: 0644
  notify: Restart uWSGI

- name: Enable app server configuration (uwsgi)
  file:
    src: "/etc/uwsgi/apps-available/{{ uwsgi_app_name }}.ini"
    dest: "/etc/uwsgi/apps-enabled/{{ uwsgi_app_name }}.ini"
    state: link
    owner: root
    group: root
  notify: Restart uWSGI

- name: Disable app server configuration (uwsgi)
  file:
    path: "/etc/uwsgi/apps-enabled/{{ uwsgi_app_name }}.ini"
    state: absent
  when: uwsgi_disable_app|bool
  notify: Restart uWSGI

Sample /etc/uwsgi-emperor/emperor.ini

[uwsgi]
emperor = /etc/uwsgi-emperor/vassals

Sample /etc/uwsgi-emperor/vassals/chemistry.ini

[uwsgi]
processes = 2
chdir = /opt/chemistry/code/chemistry
wsgi-file = chemistry/wsgi.py
virtualenv = /opt/chemistry/venv
env = DJANGO_SETTINGS_MODULE=chemistry.settings
master = true
vacuum = true
uid = chemistry
gid = chemistry
umask = 022
socket = 127.0.0.1:8125
chown-socket = chemistry:www-data
chmod-socket = 660
cpu-affinity = 1
max-requests = 5000
no-orphans = true
log-date = true
die-on-term = true
auto-procname = true
procname-prefix = chemistry|
thunder-lock = true
plugins = python3
logto = /var/log/uwsgi/vassals/chemistry.log
buffer-size = 4096
#listen = 100
#strict = true
#memory-report = true
#harakiri = 20
# For APM server
# https://www.elastic.co/guide/en/apm/agent/python/current/django-support.html
enable-threads = true
# https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy
lazy-apps = true

Issue I faced when I killed uwsgi processes

I wanted to stop a uwsgi vassal to make the service unavailalbe for Apache web server. I tried:

  1. `service uwsgi-emperor stop`
  2. `service uwsgi-emperor status`
● uwsgi-emperor.service - LSB: Start/stop uWSGI server instance(s)
 Loaded: loaded (/etc/init.d/uwsgi-emperor; generated)
 Active: active (running) since Thu 2021-06-17 12:30:06 +03; 2s ago
   Docs: man:systemd-sysv-generator(8)
Process: 1396 ExecStart=/etc/init.d/uwsgi-emperor start (code=exited, status=0/SUCCESS)
  Tasks: 10 (limit: 4701)
 Memory: 96.8M
 CGroup: /system.slice/uwsgi-emperor.service
         ├─1405 /usr/bin/uwsgi --ini /etc/uwsgi-emperor/emperor.ini --die-on-term --pidfile /run/uwsgi-emperor.pid -
         ├─1406 chemistry|uWSGI master
         ├─1407 chemistry|uWSGI worker 1
         └─1408 chemistry|uWSGI worker 2

I tried killing the processes with PID 1405, but the vassals respawned.

  1. `killall uwsgi` This killed all the uwsgi process and vassals to the service unavailable.

The issue

but I could restart the emperor and vassals properly. Even tried deleting whole uswgi-emperor and re-installing it.

The Solution

restarting the emperor with `service uwsgi-emperor restart` was resuling in

root@apps-cms-1:~# journalctl -u uwsgi-emperor -f
-- Logs begin at Thu 2021-06-17 12:22:24 +03. --
Jun 17 12:22:40 apps-cms-1 systemd[1]: Starting LSB: Start/stop uWSGI server instance(s)...
Jun 17 12:22:42 apps-cms-1 uwsgi-emperor[745]: [uWSGI] getting INI configuration from /etc/uwsgi-emperor/emperor.ini
Jun 17 12:22:42 apps-cms-1 systemd[1]: Started LSB: Start/stop uWSGI server instance(s).
Jun 17 12:23:55 apps-cms-1 systemd[1]: Stopping LSB: Start/stop uWSGI server instance(s)...
Jun 17 12:23:55 apps-cms-1 uwsgi-emperor[1214]: *start-stop-daemon: matching on world-writable pidfile /run/uwsgi-emperor.pid is insecure*

I checked the file `/run/uwsgi-emperor.pid`

cat /run/uwsgi-emperor.pid
# result: 1405

I killed this process id(pid), deleted the `/run/uwsgi-emperor.pid` and re-deployed the application with ansible, and it worked.

  • Reason(not sure)

    I killed all the uwsgi process with `killall uwsgi` but the file was referring to the already killed process, deleting the file forced uwsgi to re-creat the file with correct PID for the emperror.

The issue

During the registration a Django application, course offering, was freezing because too many students trying to access it. Backend of this service is banner-api, Django application which sqlalchemy to connect with Oracle server, which fetches the course data.

Things to try

https://www.cloudbees.com/blog/getting-every-microsecond-out-of-uwsgi ``` max-worker-lifetime = 30 ```

How uwsgi servers requests, threads, processes and optimizations?

https://www.reddit.com/r/Python/comments/4s40ge/understanding_uwsgi_threads_processes_and_gil/

Comparison of performance between uWSGI, gunicorn and other WSGI server

https://www.appdynamics.com/blog/engineering/a-performance-analysis-of-python-wsgi-servers-part-2/ Bjoern is a good option to try with Django.