main.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import logging
  2. from contextlib import asynccontextmanager
  3. from fastapi import FastAPI
  4. from starlette.middleware.cors import CORSMiddleware
  5. from tenacity import retry, stop_after_attempt, wait_fixed, before_log, after_log
  6. from app.api.v1.api import api_router
  7. from app.core.config import settings
  8. from app.core.database import Base, engine
  9. from app.core.cache import redis_client
  10. from app.core.logging_config import setup_logging
  11. from app.core.scheduler import scheduler
  12. from app.services.backup_service import BackupService
  13. from app.core.database import SessionLocal
  14. # Configure Logging
  15. logger = setup_logging()
  16. # Retry Logic Configuration
  17. max_tries = 60 * 5 # 5 minutes
  18. wait_seconds = 1
  19. @retry(
  20. stop=stop_after_attempt(max_tries),
  21. wait=wait_fixed(wait_seconds),
  22. before=before_log(logger, logging.INFO),
  23. after=after_log(logger, logging.WARN),
  24. )
  25. def init_db() -> None:
  26. try:
  27. # Try to create a connection to check if DB is ready
  28. with engine.connect() as conn:
  29. pass
  30. # Create tables
  31. Base.metadata.create_all(bind=engine)
  32. logger.info("Database connection established and tables created.")
  33. except Exception as e:
  34. logger.error(e)
  35. raise e
  36. @retry(
  37. stop=stop_after_attempt(max_tries),
  38. wait=wait_fixed(wait_seconds),
  39. before=before_log(logger, logging.INFO),
  40. after=after_log(logger, logging.WARN),
  41. )
  42. def check_redis() -> None:
  43. try:
  44. redis_client.ping()
  45. logger.info("Redis connection established.")
  46. except Exception as e:
  47. logger.error(e)
  48. raise e
  49. @asynccontextmanager
  50. async def lifespan(app: FastAPI):
  51. # Startup: Wait for services
  52. logger.info("Waiting for Database and Redis...")
  53. init_db()
  54. check_redis()
  55. # Init Scheduler
  56. logger.info("Starting Scheduler...")
  57. scheduler.start()
  58. try:
  59. with SessionLocal() as db:
  60. BackupService.init_scheduler(db)
  61. except Exception as e:
  62. logger.error(f"Failed to init scheduler: {e}")
  63. yield
  64. # Shutdown logic if any (e.g. close connections)
  65. scheduler.shutdown()
  66. logger.info("Shutting down...")
  67. app = FastAPI(
  68. title=settings.PROJECT_NAME,
  69. openapi_url=f"{settings.API_V1_STR}/openapi.json",
  70. docs_url=f"{settings.API_V1_STR}/docs",
  71. redoc_url=f"{settings.API_V1_STR}/redoc",
  72. lifespan=lifespan
  73. )
  74. # Allow all CORS for development simplicity if config is restrictive
  75. origins = [
  76. "http://localhost:5173",
  77. "http://127.0.0.1:5173",
  78. "http://localhost:8000",
  79. "http://127.0.0.1:8000"
  80. ]
  81. # Set all CORS enabled origins
  82. if settings.BACKEND_CORS_ORIGINS:
  83. for origin in settings.BACKEND_CORS_ORIGINS:
  84. origins.append(str(origin))
  85. app.add_middleware(
  86. CORSMiddleware,
  87. allow_origins=origins,
  88. allow_credentials=True,
  89. allow_methods=["*"],
  90. allow_headers=["*"],
  91. expose_headers=["X-New-Token"],
  92. )
  93. app.include_router(api_router, prefix=settings.API_V1_STR)
  94. @app.get("/")
  95. def root():
  96. return {"message": "Welcome to Unified Authentication Platform API"}