import asyncio import os from contextlib import asynccontextmanager from threading import Thread import pytz from alembic import command from alembic.config import Config from apscheduler.schedulers.asyncio import AsyncIOScheduler from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from src.controllers import bot_router, file_router, user_router from src.repositories import DatabaseConfig from src.services import ContentDeliveryService from src.utils import OpenAIClient, logger scheduler = AsyncIOScheduler() scheduler.configure({"apscheduler.timezone": pytz.timezone("America/New_York")}) @scheduler.scheduled_job("cron", hour="*", minute="*", second="*", day_of_week="mon") async def scheduled_job(): try: async with ContentDeliveryService() as content_delivery_service: await content_delivery_service.send_messages() except Exception as e: logger.error(e) def run_upgrade(connection, alembic_config: Config): alembic_config.attributes["connection"] = connection command.upgrade(alembic_config, "head") async def run_migrations(): logger.info("Running migrations if any...") alembic_config = Config("alembic.ini") alembic_config.set_main_option( "sqlalchemy.url", os.getenv("SQLALCHEMY_DATABASE_URI") ) async with DatabaseConfig.async_engine().begin() as session: await session.run_sync(run_upgrade, alembic_config) def run_scheduler(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) scheduler.start() loop.run_forever() @asynccontextmanager async def lifespan(app: FastAPI): try: logger.info("Starting up the application...") await run_migrations() scheduler_thread = Thread(target=run_scheduler, daemon=True) scheduler_thread.start() logger.info("Application started successfully...") yield except Exception as e: logger.error(f"Error during startup: {str(e)}") raise finally: logger.info("Shutting down the application...") scheduler.shutdown(wait=True) logger.info("Application shutdown complete.") app = FastAPI(lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/") async def check_health(): return {"response": "Service is healthy!"} app.include_router(bot_router, prefix="/api/v1") app.include_router(user_router, prefix="/api/v1") app.include_router(file_router, prefix="/api/v1")