Stability improvement
Gunicorn performance improved in the Docker image:
Gunicorn was creating and destroying sockets at a very fast rate (when many users are using NEMO). This was resulting in a large number of sockets remaining in the TCP TIME_WAIT or CLOSE_WAIT states, eventually choking NEMO. The culprit was a default setting in Gunicorn: keepalive = 2 seconds.
The Gunicorn process inside the Docker image now has its own configuration file: /etc/gunicorn_configuration.py. Inside this file, the keepalive is set to 60 seconds. This will work well behind a reverse proxy (Nginx). Furthermore, the Gunicorn configuration file automatically creates the appropriate number of workers based on how many CPU cores are available (workers = 2 * cpu_count + 1). This is recommended by the Gunicorn documentation and reduces the amount of performance tuning required to get NEMO working well in any production environment.