feat: dashboard integrado en thread separado + documentación
🚀 Mejoras principales: - Dashboard Flask ahora corre en thread daemon independiente - Integración con python-dotenv para variables de entorno - Configuración de puerto vía DASHBOARD_PORT (default: 5000) - Mejor logging con Thread-ID para debugging 📦 Nuevos archivos: - kubectl: binary de Kubernetes para deployments - plus.md: documentación adicional del proyecto - todo.md: roadmap y tareas pendientes 🔧 Cambios técnicos: - run_dashboard_thread(): ejecuta Flask en thread separado - start_dashboard(): crea y arranca daemon thread - Configuración de reloader desactivado en threaded mode Esto permite que el dashboard corra sin bloquear el loop principal de procesamiento, mejorando la arquitectura del servicio.
This commit is contained in:
48
main.py
48
main.py
@@ -9,10 +9,15 @@ import time
|
||||
import fcntl
|
||||
import os
|
||||
import json
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
# Load environment variables from .env file
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
# Configure logging with JSON formatter for production
|
||||
class JSONFormatter(logging.Formatter):
|
||||
"""JSON formatter for structured logging in production"""
|
||||
@@ -234,6 +239,41 @@ def send_error_notification(error_type: str, error_message: str) -> None:
|
||||
logger.warning(f"Failed to send error notification: {e}")
|
||||
|
||||
|
||||
def run_dashboard_thread() -> None:
|
||||
"""Run Flask dashboard in a separate thread"""
|
||||
try:
|
||||
from api.routes import create_app
|
||||
app = create_app()
|
||||
|
||||
# Run Flask in production mode with threaded=True
|
||||
app.run(
|
||||
host='0.0.0.0',
|
||||
port=5000,
|
||||
debug=False,
|
||||
threaded=True,
|
||||
use_reloader=False # Important: disable reloader in thread
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Dashboard thread error: {e}")
|
||||
logger.exception("Dashboard thread exception details")
|
||||
|
||||
|
||||
def start_dashboard() -> threading.Thread:
|
||||
"""Start dashboard in a background daemon thread"""
|
||||
dashboard_port = int(os.getenv('DASHBOARD_PORT', '5000'))
|
||||
logger.info(f"Starting dashboard on port {dashboard_port}...")
|
||||
|
||||
# Create daemon thread so it doesn't block shutdown
|
||||
dashboard_thread = threading.Thread(
|
||||
target=run_dashboard_thread,
|
||||
name="DashboardThread",
|
||||
daemon=True
|
||||
)
|
||||
dashboard_thread.start()
|
||||
logger.info(f"Dashboard thread started (Thread-ID: {dashboard_thread.ident})")
|
||||
return dashboard_thread
|
||||
|
||||
|
||||
def run_main_loop() -> None:
|
||||
"""Main processing loop with improved error handling"""
|
||||
from config import settings
|
||||
@@ -418,13 +458,19 @@ def run_main_loop() -> None:
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
lock_fd = None
|
||||
dashboard_thread = None
|
||||
try:
|
||||
logger.info("=== CBCFacil Service Started ===")
|
||||
logger.info(f"Version: {os.getenv('APP_VERSION', '8.0')}")
|
||||
logger.info(f"Environment: {'production' if os.getenv('DEBUG', 'false').lower() != 'true' else 'development'}")
|
||||
|
||||
|
||||
lock_fd = acquire_lock()
|
||||
initialize_services()
|
||||
|
||||
# Start dashboard in background thread
|
||||
dashboard_thread = start_dashboard()
|
||||
|
||||
# Run main processing loop
|
||||
run_main_loop()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
|
||||
Reference in New Issue
Block a user