""" Main application entry point for my-uploader-bot. Handles startup, shutdown, and application lifecycle management. """ import asyncio import signal import sys from pathlib import Path from app.api import create_app from app.core.config import get_settings from app.core.database import init_database, close_database from app.core.logging import get_logger, setup_logging from app.core.background.ton_service import cleanup_ton_service # Setup logging first setup_logging() logger = get_logger(__name__) settings = get_settings() class ApplicationManager: """Manages application lifecycle and graceful shutdown.""" def __init__(self): self.app = None self.shutdown_event = asyncio.Event() self.tasks = [] async def startup(self): """Initialize application and all services.""" try: await logger.ainfo("Starting my-uploader-bot application", version="2.0.0") # Initialize database connections await logger.ainfo("Initializing database connections") await init_database() # Create Sanic application await logger.ainfo("Creating Sanic application") self.app = await create_app() # Setup signal handlers for graceful shutdown self._setup_signal_handlers() await logger.ainfo( "Application startup completed", host=settings.HOST, port=settings.PORT, debug=settings.DEBUG, workers=settings.WORKERS ) except Exception as e: await logger.aerror("Application startup failed", error=str(e)) await self.shutdown() sys.exit(1) async def run(self): """Run the application server.""" try: if not self.app: await self.startup() # Run the Sanic server await logger.ainfo("Starting HTTP server") server_config = { "host": settings.HOST, "port": settings.PORT, "debug": settings.DEBUG, "access_log": settings.DEBUG, "auto_reload": settings.AUTO_RELOAD, "workers": settings.WORKERS if not settings.DEBUG else 1, } # Start server await self.app.create_server(**server_config, return_asyncio_server=True) # Wait for shutdown signal await self.shutdown_event.wait() except KeyboardInterrupt: await logger.ainfo("Received keyboard interrupt, shutting down") except Exception as e: await logger.aerror("Server error", error=str(e)) finally: await self.shutdown() async def shutdown(self): """Gracefully shutdown the application.""" await logger.ainfo("Initiating graceful shutdown") try: # Cancel all background tasks for task in self.tasks: if not task.done(): task.cancel() try: await task except asyncio.CancelledError: pass # Cleanup services await logger.ainfo("Cleaning up services") # Cleanup TON service await cleanup_ton_service() # Close database connections await close_database() await logger.ainfo("Graceful shutdown completed") except Exception as e: await logger.aerror("Error during shutdown", error=str(e)) def _setup_signal_handlers(self): """Setup signal handlers for graceful shutdown.""" def signal_handler(signum, frame): signal_name = signal.Signals(signum).name logger.info(f"Received {signal_name}, initiating shutdown") self.shutdown_event.set() # Register signal handlers signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # Unix-specific signals if hasattr(signal, 'SIGHUP'): signal.signal(signal.SIGHUP, signal_handler) async def main(): """Main application entry point.""" app_manager = ApplicationManager() try: await app_manager.run() except Exception as e: logger.error(f"Application failed: {e}") sys.exit(1) if __name__ == "__main__": # Ensure we're running from the correct directory app_root = Path(__file__).parent.parent if app_root.exists(): import os os.chdir(app_root) # Run the application try: asyncio.run(main()) except KeyboardInterrupt: print("\nApplication interrupted by user") sys.exit(0) except Exception as e: print(f"Failed to start application: {e}") sys.exit(1)