Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| ATOM Production Backend Server | |
| Production-ready FastAPI backend with robust process management | |
| """ | |
| import asyncio | |
| from contextlib import asynccontextmanager | |
| import logging | |
| import os | |
| import signal | |
| import sys | |
| import time | |
| from typing import Dict, List, Optional | |
| from fastapi import FastAPI, HTTPException, Request | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import JSONResponse | |
| from pydantic import BaseModel | |
| import uvicorn | |
| # Configure production logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", | |
| handlers=[ | |
| logging.StreamHandler(sys.stdout), | |
| logging.FileHandler("logs/backend_production.log"), | |
| ], | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Global state for graceful shutdown | |
| shutdown_event = asyncio.Event() | |
| # Pydantic models | |
| class HealthResponse(BaseModel): | |
| status: str | |
| service: str | |
| version: str | |
| timestamp: str | |
| message: str | |
| uptime: float | |
| class ServiceStatus(BaseModel): | |
| name: str | |
| status: str | |
| version: str | |
| endpoints: List[str] | |
| class IntegrationStatus(BaseModel): | |
| name: str | |
| status: str | |
| enabled: bool | |
| health_check: str | |
| class SystemStatus(BaseModel): | |
| overall_status: str | |
| services: List[ServiceStatus] | |
| integrations: List[IntegrationStatus] | |
| uptime: float | |
| timestamp: str | |
| # Signal handlers for graceful shutdown | |
| def signal_handler(signum, frame): | |
| """Handle shutdown signals gracefully""" | |
| logger.info(f"Received signal {signum}, initiating graceful shutdown...") | |
| shutdown_event.set() | |
| # Register signal handlers | |
| signal.signal(signal.SIGINT, signal_handler) | |
| signal.signal(signal.SIGTERM, signal_handler) | |
| async def lifespan(app: FastAPI): | |
| """Lifespan manager for startup and shutdown events""" | |
| # Startup | |
| logger.info("🚀 ATOM Production Backend Starting Up...") | |
| startup_time = time.time() | |
| # Create necessary directories | |
| os.makedirs("logs", exist_ok=True) | |
| os.makedirs("data", exist_ok=True) | |
| # Initialize services | |
| await initialize_services() | |
| logger.info("✅ ATOM Production Backend Started Successfully") | |
| yield # Application runs here | |
| # Shutdown | |
| logger.info("🛑 ATOM Production Backend Shutting Down...") | |
| await shutdown_services() | |
| uptime = time.time() - startup_time | |
| logger.info(f"📊 Backend ran for {uptime:.2f} seconds") | |
| logger.info("👋 ATOM Production Backend Shutdown Complete") | |
| async def initialize_services(): | |
| """Initialize all backend services""" | |
| logger.info("Initializing backend services...") | |
| # Service registry | |
| services = [ | |
| "Authentication Service", | |
| "Database Connection", | |
| "Integration Manager", | |
| "Task Queue", | |
| "Cache Service", | |
| ] | |
| for service in services: | |
| logger.info(f"✅ {service} initialized") | |
| await asyncio.sleep(0.1) # Simulate initialization time | |
| async def shutdown_services(): | |
| """Gracefully shutdown all services""" | |
| logger.info("Shutting down services gracefully...") | |
| services = [ | |
| "Database Connection", | |
| "Task Queue", | |
| "Cache Service", | |
| "Integration Manager", | |
| ] | |
| for service in services: | |
| logger.info(f"🛑 {service} shutdown") | |
| await asyncio.sleep(0.1) # Simulate shutdown time | |
| # Create FastAPI app with lifespan | |
| app = FastAPI( | |
| title="ATOM Production Backend", | |
| description="Advanced Task Orchestration & Management - Production API", | |
| version="2.0.0-production", | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| lifespan=lifespan, | |
| ) | |
| # CORS middleware | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=[ | |
| "http://localhost:3000", | |
| "http://127.0.0.1:3000", | |
| "http://localhost:3001", | |
| "http://127.0.0.1:3001", | |
| ], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Global startup time | |
| STARTUP_TIME = time.time() | |
| # Health check endpoint | |
| async def health_check(): | |
| """Comprehensive health check endpoint""" | |
| uptime = time.time() - STARTUP_TIME | |
| return HealthResponse( | |
| status="healthy", | |
| service="atom-production-backend", | |
| version="2.0.0", | |
| timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), | |
| message="ATOM Production Backend is running smoothly", | |
| uptime=uptime, | |
| ) | |
| # Root endpoint | |
| async def root(): | |
| """Root endpoint with system information""" | |
| uptime = time.time() - STARTUP_TIME | |
| return { | |
| "name": "ATOM Production Backend", | |
| "status": "running", | |
| "version": "2.0.0", | |
| "uptime": f"{uptime:.2f} seconds", | |
| "endpoints": { | |
| "health": "/health", | |
| "system_status": "/api/system/status", | |
| "integrations": "/api/integrations/status", | |
| "docs": "/docs", | |
| }, | |
| "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), | |
| } | |
| # System status endpoint | |
| async def system_status(): | |
| """Comprehensive system status""" | |
| uptime = time.time() - STARTUP_TIME | |
| services = [ | |
| ServiceStatus( | |
| name="Backend API", | |
| status="running", | |
| version="2.0.0", | |
| endpoints=["/health", "/api/system/status", "/api/integrations/status"], | |
| ), | |
| ServiceStatus( | |
| name="Database", | |
| status="connected", | |
| version="1.0.0", | |
| endpoints=["/api/data/*"], | |
| ), | |
| ServiceStatus( | |
| name="Authentication", | |
| status="ready", | |
| version="1.0.0", | |
| endpoints=["/api/auth/*"], | |
| ), | |
| ] | |
| integrations = [ | |
| IntegrationStatus( | |
| name="Asana", | |
| status="available", | |
| enabled=True, | |
| health_check="/api/integrations/asana/health", | |
| ), | |
| IntegrationStatus( | |
| name="Slack", | |
| status="available", | |
| enabled=True, | |
| health_check="/api/integrations/slack/health", | |
| ), | |
| IntegrationStatus( | |
| name="GitHub", | |
| status="available", | |
| enabled=True, | |
| health_check="/api/integrations/github/health", | |
| ), | |
| IntegrationStatus( | |
| name="Notion", | |
| status="available", | |
| enabled=True, | |
| health_check="/api/integrations/notion/health", | |
| ), | |
| ] | |
| return SystemStatus( | |
| overall_status="healthy", | |
| services=services, | |
| integrations=integrations, | |
| uptime=uptime, | |
| timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), | |
| ) | |
| # Integration status endpoint | |
| async def integrations_status(): | |
| """Integration status overview""" | |
| integrations = [ | |
| { | |
| "name": "Asana", | |
| "status": "ready", | |
| "endpoints": ["/api/asana/health", "/api/auth/asana/authorize"], | |
| "health": "healthy", | |
| }, | |
| { | |
| "name": "Slack", | |
| "status": "ready", | |
| "endpoints": ["/api/slack/health", "/api/auth/slack/authorize"], | |
| "health": "healthy", | |
| }, | |
| { | |
| "name": "GitHub", | |
| "status": "ready", | |
| "endpoints": ["/api/github/health", "/api/auth/github/authorize"], | |
| "health": "healthy", | |
| }, | |
| { | |
| "name": "Notion", | |
| "status": "ready", | |
| "endpoints": ["/api/notion/health", "/api/auth/notion/authorize"], | |
| "health": "healthy", | |
| }, | |
| { | |
| "name": "Jira", | |
| "status": "ready", | |
| "endpoints": ["/api/jira/health", "/api/auth/jira/authorize"], | |
| "health": "healthy", | |
| }, | |
| { | |
| "name": "Trello", | |
| "status": "ready", | |
| "endpoints": ["/api/trello/health", "/api/auth/trello/authorize"], | |
| "health": "healthy", | |
| }, | |
| ] | |
| total_integrations = len(integrations) | |
| available_integrations = len([i for i in integrations if i["health"] == "healthy"]) | |
| success_rate = (available_integrations / total_integrations) * 100 | |
| return { | |
| "ok": True, | |
| "integrations": integrations, | |
| "total_integrations": total_integrations, | |
| "available_integrations": available_integrations, | |
| "success_rate": f"{success_rate:.1f}%", | |
| "message": f"{available_integrations}/{total_integrations} integrations available", | |
| } | |
| # Mock integration endpoints | |
| async def asana_health(): | |
| """Asana integration health check""" | |
| return { | |
| "ok": True, | |
| "service": "asana", | |
| "status": "ready", | |
| "message": "Asana integration is ready for OAuth configuration", | |
| "needs_oauth": True, | |
| } | |
| async def slack_health(): | |
| """Slack integration health check""" | |
| return { | |
| "ok": True, | |
| "service": "slack", | |
| "status": "ready", | |
| "message": "Slack integration is ready for OAuth configuration", | |
| "needs_oauth": True, | |
| } | |
| async def github_health(): | |
| """GitHub integration health check""" | |
| return { | |
| "ok": True, | |
| "service": "github", | |
| "status": "ready", | |
| "message": "GitHub integration is ready for OAuth configuration", | |
| "needs_oauth": True, | |
| } | |
| # Error handling middleware | |
| async def global_exception_handler(request: Request, exc: Exception): | |
| """Global exception handler""" | |
| logger.error(f"Unhandled exception: {exc}", exc_info=True) | |
| return JSONResponse( | |
| status_code=500, | |
| content={ | |
| "ok": False, | |
| "error": { | |
| "code": "INTERNAL_ERROR", | |
| "message": "An internal server error occurred", | |
| "details": str(exc) | |
| if os.getenv("DEBUG", "false").lower() == "true" | |
| else None, | |
| }, | |
| }, | |
| ) | |
| # Graceful shutdown endpoint | |
| async def graceful_shutdown(): | |
| """Initiate graceful shutdown (protected endpoint)""" | |
| # In production, this would require authentication | |
| logger.info("Graceful shutdown initiated via API") | |
| shutdown_event.set() | |
| return {"ok": True, "message": "Shutdown initiated"} | |
| # Process monitoring endpoint | |
| async def process_info(): | |
| """Process information and metrics""" | |
| import psutil | |
| process = psutil.Process() | |
| return { | |
| "pid": process.pid, | |
| "name": process.name(), | |
| "status": process.status(), | |
| "cpu_percent": process.cpu_percent(), | |
| "memory_mb": process.memory_info().rss / 1024 / 1024, | |
| "threads": process.num_threads(), | |
| "uptime": time.time() - STARTUP_TIME, | |
| "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), | |
| } | |
| def main(): | |
| """Main entry point for production backend""" | |
| # Configuration | |
| host = os.getenv("HOST", "0.0.0.0") | |
| port = int(os.getenv("PORT", "8001")) | |
| workers = int(os.getenv("WORKERS", "1")) | |
| logger.info(f"🚀 Starting ATOM Production Backend") | |
| logger.info(f" Host: {host}") | |
| logger.info(f" Port: {port}") | |
| logger.info(f" Workers: {workers}") | |
| logger.info(f" Environment: {os.getenv('ENVIRONMENT', 'production')}") | |
| # Uvicorn configuration for production | |
| uvicorn_config = uvicorn.Config( | |
| app, | |
| host=host, | |
| port=port, | |
| workers=workers, | |
| log_level="info", | |
| access_log=True, | |
| timeout_keep_alive=5, | |
| timeout_graceful_shutdown=30, | |
| ) | |
| server = uvicorn.Server(uvicorn_config) | |
| try: | |
| server.run() | |
| except KeyboardInterrupt: | |
| logger.info("Received keyboard interrupt, shutting down...") | |
| except Exception as e: | |
| logger.error(f"Server error: {e}") | |
| sys.exit(1) | |
| finally: | |
| logger.info("ATOM Production Backend shutdown complete") | |
| if __name__ == "__main__": | |
| main() | |