Troubleshooting Supervisor Exit Status 0 Issues with Gunicorn/Django Deployment


3 views

When working with Supervisor to manage Gunicorn/Django processes, seeing "exit status 0; not expected" messages can be particularly frustrating. This typically indicates that Supervisor is successfully launching your process, but then immediately detecting that it exited cleanly (status 0) when it should remain running.

From my experience with similar deployments, several scenarios could trigger this behavior:

1. The Gunicorn command exits immediately due to configuration errors
2. Missing dependencies in the virtual environment
3. Incorrect file permissions
4. Django settings module not being found
5. Gunicorn binding to an already occupied port

First, let's modify your Supervisor config to capture more detailed logs:

[program:projectx]
command=/path/to/project/bin/gunicorn_django -c /path/to/project/project/gunicorn.conf.py /path/to/project/project/production.py
user=myuser
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/projectx.out
stderr_logfile=/var/log/projectx.err

Then test the Gunicorn command directly in your shell:

sudo -u myuser /path/to/project/bin/gunicorn_django -c /path/to/project/project/gunicorn.conf.py /path/to/project/project/production.py

Here's a working configuration I've used in production:

[program:projectx]
directory=/path/to/project
command=/path/to/project/bin/gunicorn --bind unix:/tmp/projectx.sock project.wsgi:application
user=www-data
autostart=true
autorestart=true
environment=PATH="/path/to/project/bin",DJANGO_SETTINGS_MODULE="project.settings.production"
stdout_logfile=/var/log/supervisor/projectx.log
stderr_logfile=/var/log/supervisor/projectx.err

Key differences:
- Explicit working directory
- Using gunicorn directly with WSGI application specification
- Proper environment variables
- Unix socket instead of port binding

If the direct command works but Supervisor still fails:

1. Check SELinux/AppArmor permissions
2. Verify Python path consistency between environments
3. Test with simpler gunicorn command first
4. Use strace to monitor process execution:

strace -f -o /tmp/gunicorn.trace /path/to/project/bin/gunicorn_django -c /path/to/project/project/gunicorn.conf.py /path/to/project/project/production.py

When setting up a Django application with Gunicorn under Supervisor, many developers encounter the frustrating scenario where Supervisor immediately reports the process as exited with status 0, despite Gunicorn running correctly. The key symptoms are:

INFO exited: projectx (exit status 0; not expected)
INFO gave up: projectx entered FATAL state

Supervisor expects managed processes to remain in the foreground. However, Gunicorn (especially with certain configurations) might daemonize itself or fork worker processes in ways that make Supervisor lose track of the main process.

Here's a corrected configuration that prevents this issue:

[program:projectx]
command=/path/to/venv/bin/gunicorn --bind 0.0.0.0:8000 --pid /var/run/gunicorn.pid --workers 3 --timeout 120 --access-logfile - --error-logfile - --capture-output --enable-stdio-inheritance project.wsgi:application
directory=/path/to/project
user=deploy
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/projectx.log
stderr_logfile=/var/log/supervisor/projectx_err.log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8

Several key parameters make this work:

  • --pid: Helps Supervisor track the process
  • --capture-output: Ensures logging works correctly
  • --enable-stdio-inheritance: Maintains proper process communication
  • redirect_stderr: Combines error and output streams

For more complex setups, use a dedicated Gunicorn config file:

# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 3
timeout = 120
pidfile = "/var/run/gunicorn.pid"
accesslog = "-"
errorlog = "-"
capture_output = True
enable_stdio_inheritance = True
daemon = False  # Critical for Supervisor compatibility

Then modify the Supervisor config:

[program:projectx]
command=/path/to/venv/bin/gunicorn -c /path/to/gunicorn.conf.py project.wsgi:application

After implementing these changes:

  1. Reload Supervisor: sudo supervisorctl reread
  2. Update config: sudo supervisorctl update
  3. Check status: sudo supervisorctl status

You should now see your process running normally without unexpected exits.