Running Your Application¶
This guide explains how to run your Wiverno application in different environments, from development to production.
Overview¶
Wiverno provides two server options:
- DevServer - Development server with hot reload (automatic restart on code changes)
- RunServer - Production-ready WSGI server for deploying applications
Development Server (DevServer)¶
The DevServer is designed for local development and includes hot reload functionality. When you modify your Python files, the server automatically restarts to reflect the changes.
Basic Usage¶
This starts the server with default settings:
- Module:
run(looks forrun.py) - App name:
app(looks forappvariable) - Host:
localhost - Port:
8000
Custom Configuration¶
DevServer.serve(
app_module="myapp", # Module containing your app
app_name="application", # Variable name of your app
host="0.0.0.0", # Bind to all interfaces
port=8080 # Custom port
)
Advanced Usage¶
For more control, create a DevServer instance:
from wiverno.dev.dev_server import DevServer
server = DevServer(
app_module="myapp",
app_name="app",
host="localhost",
port=8000,
watch_dirs=["./myapp", "./shared"], # Watch multiple directories
ignore_patterns=[ # Custom ignore patterns
"__pycache__",
".venv",
"tests",
"*.pyc",
],
debounce_seconds=1.0, # Wait time before restart
)
# For advanced usage, instantiate and configure before serving
# Then use serve() static method for actual startup
How Hot Reload Works¶
- Watchdog monitors
.pyfiles in specified directories - When a file is modified, a
FileSystemEventis triggered - Debounce mechanism waits 1 second to collect all changes
- After the delay, server restart is initiated
- Old server process is properly terminated
- New process starts with updated code
- Restart counter increments for tracking
Ignored Patterns¶
By default, DevServer ignores:
__pycache__/- Python cache directories.venv/,venv/- Virtual environments.git/- Git repository.pytest_cache/,.mypy_cache/,.ruff_cache/- Tool cachestests/- Test directorieshtmlcov/,.coverage- Coverage files
Example Development Setup¶
Create a dev.py file in your project:
from wiverno.dev.dev_server import DevServer
if __name__ == "__main__":
DevServer.serve(
app_module="app",
app_name="app",
host="0.0.0.0",
port=8000,
)
Run it:
Using with CLI¶
The CLI provides a convenient way to run the dev server:
# Start development server
wiverno run dev
# With custom host and port
wiverno run dev --host 0.0.0.0 --port 8000
# With custom module
wiverno run dev --app-module myapp --app-name application
Production Server (RunServer)¶
The RunServer is an improved WSGI server suitable for production deployments. It includes graceful shutdown, better error handling, and production-ready features.
Basic Usage¶
from wiverno.core.server import RunServer
from myapp import app
server = RunServer(app, host="0.0.0.0", port=8000)
server.start()
Configuration Options¶
server = RunServer(
application=app, # Your WSGI application
host="0.0.0.0", # Bind to all interfaces
port=8000, # Port number
request_queue_size=5, # Max queued connections
)
Features¶
Graceful Shutdown¶
RunServer handles SIGINT (Ctrl+C) and SIGTERM signals gracefully:
server = RunServer(app)
server.start() # Server runs until interrupted
# On Ctrl+C or kill signal:
# 1. Current requests are completed
# 2. Server shuts down cleanly
# 3. Resources are released
You can also stop the server programmatically:
Enhanced Logging¶
RunServer provides detailed logging:
import logging
logging.basicConfig(level=logging.INFO)
server = RunServer(app, host="0.0.0.0", port=8000)
server.start()
# Logs:
# INFO: Wiverno server started on http://0.0.0.0:8000
# INFO: Request queue size: 5
# INFO: Press Ctrl+C to stop the server
Error Handling¶
The server handles common errors:
try:
server = RunServer(app, host="0.0.0.0", port=80)
server.start()
except OSError as e:
print(f"Cannot bind to port 80: {e}")
# Permission denied or port already in use
Example Production Setup¶
Create a run.py file:
import logging
from wiverno.core.server import RunServer
from myapp import app
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
if __name__ == "__main__":
server = RunServer(
app,
host="0.0.0.0",
port=8000,
request_queue_size=10, # Handle more concurrent connections
)
try:
server.start()
except KeyboardInterrupt:
print("Server stopped")
Run it:
Using with CLI¶
# Start production server
wiverno run prod
# With custom configuration
wiverno run prod --host 0.0.0.0 --port 8000
Production Deployment Recommendations¶
For Light to Medium Traffic¶
RunServer is suitable for light to medium traffic applications:
Pros:
- Built-in, no extra dependencies
- Graceful shutdown
- Easy to configure
- Good error handling
Cons:
- Single-threaded (no concurrency)
- Not optimized for high traffic
- Limited performance tuning options
For High Traffic (Recommended)¶
For production environments with high traffic, use dedicated WSGI servers:
Gunicorn (Linux/Unix)¶
Waitress (Cross-platform)¶
uWSGI (Linux/Unix)¶
Comparison Table¶
| Feature | DevServer | RunServer | Gunicorn/uWSGI |
|---|---|---|---|
| Purpose | Development | Light production | Heavy production |
| Hot Reload | ✅ Yes | ❌ No | ❌ No |
| Multi-process | ❌ No | ❌ No | ✅ Yes |
| Graceful Shutdown | ✅ Yes | ✅ Yes | ✅ Yes |
| Performance | Low | Medium | High |
| Ease of Use | Very Easy | Easy | Moderate |
| Dependencies | watchdog, rich | None | Extra package |
Best Practices¶
Development¶
- Use DevServer for all development work
- Don't use DevServer in production - it's not designed for it
- Configure ignore patterns to avoid unnecessary restarts
- Use appropriate debounce time (1 second is usually good)
Example:
# dev.py
from wiverno.dev.dev_server import DevServer
if __name__ == "__main__":
DevServer.serve(
app_module="myapp",
host="127.0.0.1", # Only localhost in dev
port=8000,
)
Production¶
- Test with RunServer first before moving to Gunicorn/uWSGI
- Use RunServer for small applications or prototypes
- Use Gunicorn/uWSGI/Waitress for production applications
- Enable proper logging for debugging
- Use reverse proxy (nginx, Apache) in front of your WSGI server
- Monitor resource usage and adjust workers/threads accordingly
Example:
# run.py
import logging
from wiverno.core.server import RunServer
from myapp import app
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
)
if __name__ == "__main__":
server = RunServer(app, host="0.0.0.0", port=8000)
server.start()
Systemd Service (Linux)¶
Create /etc/systemd/system/wiverno-app.service:
[Unit]
Description=Wiverno Application
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/.venv/bin"
ExecStart=/var/www/myapp/.venv/bin/python run.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl enable wiverno-app
sudo systemctl start wiverno-app
sudo systemctl status wiverno-app
Docker Deployment¶
Dockerfile Example¶
FROM python:3.12-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Expose port
EXPOSE 8000
# Run with RunServer (for simple apps)
CMD ["python", "run.py"]
# Or use Gunicorn for production
# CMD ["gunicorn", "myapp:app", "--workers=4", "--bind=0.0.0.0:8000"]
Docker Compose Example¶
version: "3.8"
services:
web:
build: .
ports:
- "8000:8000"
environment:
- PYTHONUNBUFFERED=1
volumes:
- .:/app # For development with hot reload
# Remove volumes in production
Troubleshooting¶
Port Already in Use¶
# Error: OSError: [Errno 98] Address already in use
# Solution: Use a different port or kill the process using the port
# Find process:
# lsof -i :8000
# Kill process:
# kill -9 <PID>
Hot Reload Not Working¶
- Check that you're using DevServer, not RunServer
- Verify file patterns are not in ignore list
- Make sure files are being saved properly
- Check console for error messages
Permission Denied on Port 80/443¶
# Ports below 1024 require root privileges
# Option 1: Use port >= 1024 (recommended)
DevServer.serve(port=8000)
# Option 2: Use sudo (not recommended)
sudo python dev.py
# Option 3: Use reverse proxy (best for production)
# nginx -> localhost:8000
High Memory Usage in Production¶
RunServer is single-threaded, but if you see high memory usage:
- Check for memory leaks in your application code
- Monitor with tools like
htoporps - Consider using Gunicorn with multiple workers:
Summary¶
- DevServer: Development with hot reload - use
DevServer.serve() - RunServer: Light production - use for small apps or prototypes
- Gunicorn/uWSGI/Waitress: Heavy production - use for production applications
- Always use proper logging and monitoring in production
- Test thoroughly before deploying to production
Next Steps¶
- Learn about CLI commands for quick server management
- Explore Routing to define your application endpoints
- Read about Requests to handle incoming data