Enhanced: Comprehensive production debugging and Nginx proxy support

Debugging Tools:
- Added /debug endpoint to verify deployment and test distribution functionality
- Added browser console test function: testDistributionChart()
- Enhanced SocketIO settings with better transport priorities
- Added comprehensive error tracking and status reporting

Nginx Configuration:
- Created NGINX_CONFIG.md with complete proxy setup guide
- Improved WebSocket transport settings and timeouts
- Better ping/pong settings for connection stability

Production Compatibility:
- Optimized SocketIO for proxy environments
- Enhanced fallback mechanisms
- Production-ready logging and error handling

This should resolve proxy-related issues and provide clear diagnostic tools.
This commit is contained in:
2025-08-24 18:53:09 +00:00
parent 6f94b1bd04
commit 97e9e18ee5
4 changed files with 211 additions and 3 deletions

88
NGINX_CONFIG.md Normal file
View File

@@ -0,0 +1,88 @@
# Nginx Configuration for Flask-SocketIO with WebSocket Support
This document provides the required Nginx configuration to properly proxy WebSocket connections for the Markov Economics application.
## Required Nginx Configuration
```nginx
server {
listen 80;
server_name markov.elpatron.me;
# Optional: Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name markov.elpatron.me;
# SSL configuration (adjust paths as needed)
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/private.key;
# WebSocket proxy settings
location /socket.io/ {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket specific timeouts
proxy_read_timeout 86400;
proxy_send_timeout 86400;
proxy_connect_timeout 60;
# Disable buffering for real-time communication
proxy_buffering off;
proxy_cache off;
}
# Regular HTTP traffic
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Standard timeouts
proxy_read_timeout 30;
proxy_send_timeout 30;
proxy_connect_timeout 10;
}
}
```
## Critical Configuration Points
1. **WebSocket Upgrade Headers**: The `Upgrade` and `Connection` headers are essential for WebSocket handshake
2. **HTTP Version**: Must use HTTP/1.1 for WebSocket support
3. **Extended Timeouts**: WebSocket connections need longer timeouts than regular HTTP
4. **Disable Buffering**: Real-time communication requires immediate data flow
5. **Separate Location Blocks**: Socket.IO traffic should be handled separately from regular HTTP traffic
## Testing the Configuration
After applying the configuration:
1. Restart Nginx: `sudo nginx -t && sudo systemctl reload nginx`
2. Check browser console for connection messages
3. Test the debug endpoint: https://markov.elpatron.me/debug
4. Run the distribution test: Open browser console and type `testDistributionChart()`
## Troubleshooting
If WebSocket connections still fail:
- Check Nginx error logs: `sudo tail -f /var/log/nginx/error.log`
- Verify the application is accessible directly: `curl http://127.0.0.1:5000/health`
- Test WebSocket connection manually with tools like `wscat`
- Ensure firewall allows WebSocket traffic
## Alternative: Fallback to Polling Only
If WebSocket cannot be made to work, the application will automatically fall back to HTTP polling, which should work with any standard HTTP proxy configuration.

View File

@@ -15,8 +15,13 @@ from app.models import SimulationManager
socketio = SocketIO(
cors_allowed_origins="*",
async_mode='threading',
logger=True,
engineio_logger=True
logger=False, # Disable to avoid log spam in production
engineio_logger=False,
# Transport order: try websocket first, then polling
transports=['websocket', 'polling'],
# Ping settings for better connection detection
ping_timeout=60,
ping_interval=25
)
# Global simulation manager instance
@@ -45,7 +50,9 @@ def create_app(config_name=None):
async_mode='threading',
cors_allowed_origins="*",
allow_upgrades=True,
transports=['websocket', 'polling']
transports=['websocket', 'polling'],
ping_timeout=60,
ping_interval=25
)
# Register blueprints

View File

@@ -101,6 +101,59 @@ def results(simulation_id):
title=f"Results - Simulation {simulation_id[:8]}")
@main_bp.route('/debug')
def debug_info():
"""
Debug endpoint to verify deployment and test functionality.
Returns:
JSON response with debug information
"""
import os
from datetime import datetime
from app.models.economic_model import EconomicSimulation, SimulationParameters
# Test distribution functionality
test_params = SimulationParameters(
r_rate=0.05,
g_rate=0.03,
initial_capital=1000,
initial_consumption=1000,
num_agents=10,
iterations=5
)
test_sim = EconomicSimulation(test_params)
# Run a few steps
for _ in range(5):
test_sim.step()
# Get distribution data
labels, counts = test_sim.get_wealth_histogram(5)
debug_data = {
'timestamp': datetime.now().isoformat(),
'environment': os.getenv('FLASK_ENV', 'unknown'),
'config': os.getenv('FLASK_CONFIG', 'unknown'),
'python_version': os.sys.version,
'distribution_test': {
'labels': labels,
'counts': counts,
'total_agents': len(test_sim.agents),
'snapshots': len(test_sim.snapshots)
},
'fixes_deployed': {
'fallback_polling': True,
'enhanced_socketio': True,
'production_debug': True,
'environment_fix': True
},
'version_info': 'v2.1-proxy-fixes'
}
return jsonify(debug_data)
@main_bp.route('/health')
def health_check():
"""

View File

@@ -1,3 +1,63 @@
/**
* Production debugging test function
* Call from browser console: testDistributionChart()
*/
window.testDistributionChart = function() {
debugLog('=== DISTRIBUTION CHART DIAGNOSTIC TEST ===');
// Test 1: Check if elements exist
const canvas = document.getElementById('distributionChart');
debugLog('Canvas element found', !!canvas);
// Test 2: Check Chart.js availability
debugLog('Chart.js available', typeof Chart !== 'undefined');
// Test 3: Check chart instance
debugLog('Chart instance exists', !!charts.distribution);
// Test 4: Check current data
debugLog('Current simulation data', {
hasId: !!currentSimulation.id,
isRunning: currentSimulation.isRunning,
distributionData: currentSimulation.data.distribution
});
// Test 5: Check WebSocket connection
debugLog('WebSocket status', {
socketExists: !!window.MarkovEconomics.socket,
isConnected: window.MarkovEconomics ? window.MarkovEconomics.isConnected : 'unknown'
});
// Test 6: Manually test API endpoint
if (currentSimulation.id) {
fetch(`/api/simulation/${currentSimulation.id}/distribution?bins=5`)
.then(response => response.json())
.then(data => {
debugLog('Manual API test result', data);
})
.catch(error => {
debugLog('Manual API test failed', error);
});
}
// Test 7: Try to create test data and update chart
if (charts.distribution) {
const testLabels = ['$0-100', '$100-200', '$200-300'];
const testCounts = [5, 8, 2];
try {
charts.distribution.data.labels = testLabels;
charts.distribution.data.datasets[0].data = testCounts;
charts.distribution.update();
debugLog('Manual chart update test: SUCCESS');
} catch (error) {
debugLog('Manual chart update test: FAILED', error);
}
}
debugLog('=== TEST COMPLETE ===');
};
// Debug flag - can be enabled even in production for troubleshooting
const DEBUG_DISTRIBUTION = true;