Implement proper error boundaries to prevent app crashes

Frontend Error Boundaries:
- Created ErrorBoundary class for centralized error handling
- Wraps critical functions (transcribe, translate, TTS) with error boundaries
- Global error handlers for unhandled errors and promise rejections
- Component-specific error recovery with fallback functions
- User-friendly error notifications with auto-dismiss
- Error logging to backend for monitoring
- Prevents cascading failures from component errors

Backend Error Handling:
- Added error boundary decorator for Flask routes
- Global Flask error handlers (404, 500, generic exceptions)
- Frontend error logging endpoint (/api/log-error)
- Structured error responses with component information
- Full traceback logging for debugging
- Production vs development error message handling

Features:
- Graceful degradation when components fail
- Automatic error recovery attempts
- Error history tracking (last 50 errors)
- Component-specific error handling
- Production error monitoring ready
- Prevents full app crashes from isolated errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-06-02 22:47:43 -06:00
parent 0c9186e57e
commit 3804897e2b
3 changed files with 454 additions and 9 deletions

86
app.py
View File

@@ -15,11 +15,33 @@ from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
import gc # For garbage collection
from functools import wraps
import traceback
# Initialize logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Error boundary decorator for Flask routes
def with_error_boundary(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
# Log the full exception with traceback
logger.error(f"Error in {func.__name__}: {str(e)}")
logger.error(traceback.format_exc())
# Return appropriate error response
error_message = str(e) if app.debug else "An internal error occurred"
return jsonify({
'success': False,
'error': error_message,
'component': func.__name__
}), 500
return wrapper
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = tempfile.mkdtemp()
app.config['TTS_SERVER'] = os.environ.get('TTS_SERVER_URL', 'http://localhost:5050/v1/audio/speech')
@@ -623,6 +645,29 @@ def get_audio(filename):
logger.error(f"Audio retrieval error: {str(e)}")
return jsonify({'error': f'Audio retrieval failed: {str(e)}'}), 500
# Error logging endpoint for frontend error reporting
@app.route('/api/log-error', methods=['POST'])
def log_error():
"""Log frontend errors for monitoring"""
try:
error_data = request.json
error_info = error_data.get('errorInfo', {})
error_details = error_data.get('error', {})
# Log the error
logger.error(f"Frontend error in {error_info.get('component', 'unknown')}: {error_details.get('message', 'No message')}")
logger.error(f"Stack trace: {error_details.get('stack', 'No stack trace')}")
logger.error(f"User agent: {error_info.get('userAgent', 'Unknown')}")
logger.error(f"URL: {error_info.get('url', 'Unknown')}")
# In production, you might want to send this to a monitoring service
# like Sentry, LogRocket, or your own analytics
return jsonify({'success': True})
except Exception as e:
logger.error(f"Failed to log frontend error: {str(e)}")
return jsonify({'success': False, 'error': str(e)}), 500
# Health check endpoints for monitoring
@app.route('/health', methods=['GET'])
def health_check():
@@ -741,5 +786,46 @@ app.request_count = 0
def before_request():
app.request_count = getattr(app, 'request_count', 0) + 1
# Global error handlers
@app.errorhandler(404)
def not_found_error(error):
logger.warning(f"404 error: {request.url}")
return jsonify({
'success': False,
'error': 'Resource not found',
'status': 404
}), 404
@app.errorhandler(500)
def internal_error(error):
logger.error(f"500 error: {str(error)}")
logger.error(traceback.format_exc())
return jsonify({
'success': False,
'error': 'Internal server error',
'status': 500
}), 500
@app.errorhandler(Exception)
def handle_exception(error):
# Log the error
logger.error(f"Unhandled exception: {str(error)}")
logger.error(traceback.format_exc())
# Return JSON instead of HTML for HTTP errors
if hasattr(error, 'code'):
return jsonify({
'success': False,
'error': str(error),
'status': error.code
}), error.code
# Non-HTTP exceptions
return jsonify({
'success': False,
'error': 'An unexpected error occurred',
'status': 500
}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5005, debug=True)