-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
168 lines (129 loc) · 4.98 KB
/
Copy pathmain.py
File metadata and controls
168 lines (129 loc) · 4.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"""Main application entry point for Cortex API.
This module sets up the FastAPI application with all necessary configurations,
middleware, and routes for the Engineering Thinking Training Platform.
"""
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi_crons import Crons, get_cron_router
from contextlib import asynccontextmanager
import time
from database import connect_to_mongo, close_mongo_connection
from routers import auth, users, tasks, responses, progress, drills, admin, subscriptions, webhooks
from config import settings
from logger import get_logger
from utils.rate_limit import limiter
from slowapi.errors import RateLimitExceeded
from slowapi import _rate_limit_exceeded_handler
logger = get_logger(__name__)
# Initialize cron jobs instance at module level
crons = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Manage application lifecycle: startup and shutdown events.
This context manager handles:
- Startup: Establish MongoDB connection and start cron jobs
- Shutdown: Stop cron jobs and close MongoDB connection gracefully
Args:
app: The FastAPI application instance
"""
global crons
logger.info("Starting Cortex API server...")
# Startup: Connect to MongoDB database
await connect_to_mongo()
logger.info("Database connection established")
# Start cron scheduler
if crons:
await crons.start()
logger.cron("CRON SCHEDULER STARTED")
logger.cron("Registered job: daily_task_generation (0 0 * * * = midnight UTC)")
yield
# Shutdown: Stop cron jobs and clean up database connections
logger.info("Shutting down Cortex API server...")
if crons:
await crons.stop()
logger.cron("CRON SCHEDULER STOPPED")
await close_mongo_connection()
logger.info("Database connection closed")
app = FastAPI(
title="Cortex API",
description="Engineering Thinking Training Platform",
version="1.0.0",
lifespan=lifespan
)
# Add slowapi limiter to app state
app.state.limiter = limiter
# Add exception handler for rate limiting
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# Initialize cron jobs manager
crons = Crons(app)
# Add cron management endpoints
app.include_router(get_cron_router(), prefix="/api/crons", tags=["Cron Jobs"])
@app.middleware("http")
async def log_requests(request: Request, call_next):
"""Log all incoming requests and their processing time."""
start_time = time.time()
# Log request
logger.info(f"-> {request.method} {request.url.path} | Client: {request.client.host}")
# Process request
response = await call_next(request)
# Calculate processing time
process_time = (time.time() - start_time) * 1000
# Log response
logger.info(
f"<- {request.method} {request.url.path} | "
f"Status: {response.status_code} | "
f"Time: {process_time:.2f}ms"
)
return response
# CORS configuration
# Parse allowed origins from comma-separated string
# Use "*" in development, specific domains in production
cors_origins = (
["*"] if settings.allowed_origins == "*"
else [origin.strip() for origin in settings.allowed_origins.split(",") if origin.strip()]
)
app.add_middleware(
CORSMiddleware,
allow_origins=cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"])
app.include_router(users.router, prefix="/api/users", tags=["Users"])
app.include_router(tasks.router, prefix="/api/tasks", tags=["Tasks"])
app.include_router(responses.router, prefix="/api/responses", tags=["Responses"])
app.include_router(progress.router, prefix="/api/progress", tags=["Progress"])
app.include_router(drills.router, prefix="/api/drills", tags=["Thinking Drills"])
app.include_router(admin.router, prefix="/api/admin", tags=["Admin"])
app.include_router(subscriptions.router, prefix="/api/subscriptions", tags=["Subscriptions"])
app.include_router(webhooks.router, prefix="/api/webhooks", tags=["Webhooks"])
# Register cron jobs with decorator
from cron_jobs import daily_task_generation_job
@crons.cron("0 0 * * *", name="daily_task_generation")
async def scheduled_task_generation():
"""Runs at midnight every day to generate tasks for all roles."""
return await daily_task_generation_job()
@app.get("/")
async def root():
"""Root endpoint to verify API is running.
Returns:
dict: API status information including name, version, and status
"""
return {
"message": "Cortex API - Engineering Thinking Training Platform",
"version": "1.0.0",
"status": "active"
}
@app.get("/api/health")
async def health_check():
return {"status": "healthy"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host=settings.host,
port=settings.port,
reload=True
)