Make Gunicorn respect config.json settings
- Updated gunicorn.conf.py to read host/port from config.json - Added gunicorn section to config.json for server settings - Created start_gunicorn.py as alternative launcher - Updated config.json with server settings (127.0.0.1:6969) - Updated documentation with new startup options
This commit is contained in:
@@ -35,7 +35,7 @@ python config_manager.py rate_limiting.endpoints.login "10 per minute"
|
||||
|
||||
## Running with Gunicorn (Production)
|
||||
|
||||
### Quick Start
|
||||
### Quick Start - Uses config.json settings
|
||||
```bash
|
||||
# Activate virtual environment
|
||||
source .venv/bin/activate
|
||||
@@ -43,25 +43,28 @@ source .venv/bin/activate
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run with Gunicorn (recommended for production)
|
||||
# Option 1: Run with config file (recommended - uses config.json)
|
||||
gunicorn --config gunicorn.conf.py app:app
|
||||
|
||||
# Option 2: Run with Python launcher (also uses config.json)
|
||||
python start_gunicorn.py
|
||||
```
|
||||
|
||||
### Alternative Gunicorn Commands
|
||||
### Manual Gunicorn Commands (ignores config.json)
|
||||
|
||||
**Basic production run:**
|
||||
```bash
|
||||
gunicorn -w 4 -b 0.0.0.0:5050 app:app
|
||||
gunicorn -w 4 -b 127.0.0.1:6969 app:app
|
||||
```
|
||||
|
||||
**With more workers (for higher traffic):**
|
||||
```bash
|
||||
gunicorn -w 8 -b 0.0.0.0:5050 --timeout 30 app:app
|
||||
gunicorn -w 8 -b 127.0.0.1:6969 --timeout 30 app:app
|
||||
```
|
||||
|
||||
**Behind a reverse proxy (nginx/apache):**
|
||||
```bash
|
||||
gunicorn -w 4 -b 127.0.0.1:5050 app:app
|
||||
gunicorn -w 4 -b 127.0.0.1:6969 app:app
|
||||
```
|
||||
|
||||
### Environment Variables for Production
|
||||
|
||||
11
config.json
11
config.json
@@ -1,10 +1,17 @@
|
||||
{
|
||||
"app": {
|
||||
"name": "ircquotes",
|
||||
"host": "0.0.0.0",
|
||||
"port": 5050,
|
||||
"host": "127.0.0.1",
|
||||
"port": 6969,
|
||||
"debug": false
|
||||
},
|
||||
"gunicorn": {
|
||||
"workers": 4,
|
||||
"timeout": 30,
|
||||
"keepalive": 5,
|
||||
"max_requests": 1000,
|
||||
"preload": true
|
||||
},
|
||||
"database": {
|
||||
"uri": "sqlite:///quotes.db?timeout=20",
|
||||
"pool_timeout": 20,
|
||||
|
||||
@@ -1,21 +1,42 @@
|
||||
# Gunicorn configuration file for ircquotes
|
||||
import multiprocessing
|
||||
import json
|
||||
import os
|
||||
|
||||
# Server socket
|
||||
bind = "0.0.0.0:5050"
|
||||
# Load configuration from config.json
|
||||
def load_app_config():
|
||||
config_file = os.path.join(os.path.dirname(__file__), 'config.json')
|
||||
try:
|
||||
with open(config_file, 'r') as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
# Fallback to defaults if config.json not found
|
||||
return {
|
||||
"app": {"host": "0.0.0.0", "port": 5050}
|
||||
}
|
||||
|
||||
app_config = load_app_config()
|
||||
|
||||
# Server socket - use config.json values
|
||||
host = app_config.get('app', {}).get('host', '0.0.0.0')
|
||||
port = app_config.get('app', {}).get('port', 5050)
|
||||
bind = f"{host}:{port}"
|
||||
backlog = 2048
|
||||
|
||||
# Worker processes
|
||||
workers = multiprocessing.cpu_count() * 2 + 1
|
||||
# Worker processes - use config.json values
|
||||
workers = app_config.get('gunicorn', {}).get('workers', multiprocessing.cpu_count() * 2 + 1)
|
||||
worker_class = "sync"
|
||||
worker_connections = 1000
|
||||
timeout = 30
|
||||
keepalive = 5
|
||||
timeout = app_config.get('gunicorn', {}).get('timeout', 30)
|
||||
keepalive = app_config.get('gunicorn', {}).get('keepalive', 5)
|
||||
|
||||
# Restart workers after this many requests, to help prevent memory leaks
|
||||
max_requests = 1000
|
||||
max_requests = app_config.get('gunicorn', {}).get('max_requests', 1000)
|
||||
max_requests_jitter = 100
|
||||
|
||||
# Preload app for better performance
|
||||
preload_app = app_config.get('gunicorn', {}).get('preload', True)
|
||||
|
||||
# Logging
|
||||
accesslog = "-" # Log to stdout
|
||||
errorlog = "-" # Log to stderr
|
||||
|
||||
49
start_gunicorn.py
Normal file
49
start_gunicorn.py
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Gunicorn launcher that reads configuration from config.json
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from config_loader import config
|
||||
|
||||
def main():
|
||||
"""Launch Gunicorn with settings from config.json"""
|
||||
|
||||
# Get configuration values
|
||||
host = config.app_host
|
||||
port = config.app_port
|
||||
workers = config.get('gunicorn.workers', 4)
|
||||
|
||||
# Build Gunicorn command
|
||||
cmd = [
|
||||
'gunicorn',
|
||||
'--bind', f'{host}:{port}',
|
||||
'--workers', str(workers),
|
||||
'--timeout', '30',
|
||||
'--keepalive', '5',
|
||||
'--max-requests', '1000',
|
||||
'--max-requests-jitter', '100',
|
||||
'--access-logfile', '-',
|
||||
'--error-logfile', '-',
|
||||
'--log-level', 'info',
|
||||
'--preload',
|
||||
'app:app'
|
||||
]
|
||||
|
||||
print(f"Starting Gunicorn on {host}:{port} with {workers} workers...")
|
||||
print(f"Command: {' '.join(cmd)}")
|
||||
|
||||
# Execute Gunicorn
|
||||
try:
|
||||
subprocess.run(cmd, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error starting Gunicorn: {e}")
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
print("\nStopping Gunicorn...")
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user