Refactor: Improve MongoDB connection and add certifi

Co-authored-by: mathieumoran1 <[email protected]>
This commit is contained in:
Cursor Agent
2025-12-22 09:00:41 +00:00
co-authored by mathieumoran1
parent 98f40488aa
commit 7cffe9db58
3 changed files with 69 additions and 8 deletions
+1
View File
@@ -3,3 +3,4 @@ uvicorn[standard]==0.34.0
pymongo==4.10.1 pymongo==4.10.1
PyJWT==2.10.1 PyJWT==2.10.1
certbot>=2.11.0,<3 certbot>=2.11.0,<3
certifi==2025.11.12
+62 -2
View File
@@ -1,6 +1,7 @@
import mimetypes import mimetypes
import os import os
import posixpath import posixpath
from functools import lru_cache
from datetime import datetime, timezone from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from typing import Generator, Optional, Tuple from typing import Generator, Optional, Tuple
@@ -13,6 +14,7 @@ from fastapi import FastAPI, Header, HTTPException, Request, Response
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, StreamingResponse from fastapi.responses import FileResponse, StreamingResponse
from pymongo import MongoClient from pymongo import MongoClient
from pymongo.errors import PyMongoError
def _env_str(name: str, default: str = "") -> str: def _env_str(name: str, default: str = "") -> str:
@@ -49,6 +51,12 @@ def _mongo_db_name() -> str:
except Exception: except Exception:
return "" return ""
def _env_int(name: str, default: int) -> int:
try:
return int(_env_str(name, str(default)))
except Exception:
return default
def _video_files_dir() -> Path: def _video_files_dir() -> Path:
# Read env at runtime (important on Windows/uvicorn worker reloads). # Read env at runtime (important on Windows/uvicorn worker reloads).
@@ -143,7 +151,38 @@ def _mongo_client() -> MongoClient:
uri = _mongo_uri() uri = _mongo_uri()
if not uri: if not uri:
raise HTTPException(status_code=500, detail="MONGO_URI is not configured") raise HTTPException(status_code=500, detail="MONGO_URI is not configured")
return MongoClient(uri) kwargs = {
# Fail fast instead of hanging for ~30s on each request.
"serverSelectionTimeoutMS": _env_int("MONGO_SERVER_SELECTION_TIMEOUT_MS", 8000),
"connectTimeoutMS": _env_int("MONGO_CONNECT_TIMEOUT_MS", 8000),
"socketTimeoutMS": _env_int("MONGO_SOCKET_TIMEOUT_MS", 20000),
}
# On some hosts, the system CA store is missing/broken or overridden by env vars,
# causing TLS handshake failures to MongoDB Atlas. Prefer certifi's CA bundle.
ca_file = _env_str("MONGO_TLS_CA_FILE")
if ca_file:
kwargs["tlsCAFile"] = ca_file
else:
try:
import certifi # type: ignore
kwargs["tlsCAFile"] = certifi.where()
except Exception:
# If certifi isn't available, fall back to system trust.
pass
# Optional escape hatch (NOT recommended): allow invalid certs for debugging only.
if _env_str("MONGO_TLS_INSECURE", "0") in ("1", "true", "yes", "on"):
kwargs["tlsAllowInvalidCertificates"] = True
return MongoClient(uri, **kwargs)
@lru_cache(maxsize=1)
def _mongo_client_cached() -> MongoClient:
# Reuse one client (connection pool) across requests.
return _mongo_client()
app = FastAPI() app = FastAPI()
@@ -211,15 +250,26 @@ def stream_video(
except Exception: except Exception:
raise HTTPException(status_code=400, detail="Invalid movie id") raise HTTPException(status_code=400, detail="Invalid movie id")
with _mongo_client() as client:
db_name = _mongo_db_name() db_name = _mongo_db_name()
if not db_name: if not db_name:
raise HTTPException( raise HTTPException(
status_code=500, status_code=500,
detail="Mongo DB name not configured. Add it to MONGO_URI (…/dbname) or set MONGO_DB_NAME.", detail="Mongo DB name not configured. Add it to MONGO_URI (…/dbname) or set MONGO_DB_NAME.",
) )
try:
client = _mongo_client_cached()
db = client[db_name] db = client[db_name]
movie = db["movies"].find_one({"_id": oid}, {"video_file": 1}) movie = db["movies"].find_one({"_id": oid}, {"video_file": 1})
except PyMongoError as e:
raise HTTPException(
status_code=502,
detail=(
"Failed to query MongoDB (TLS/connection issue). "
"On some hosts you may need a CA bundle; try installing certifi or set MONGO_TLS_CA_FILE. "
f"Original error: {type(e).__name__}: {e}"
),
)
video_file = (movie or {}).get("video_file") or "" video_file = (movie or {}).get("video_file") or ""
if not isinstance(video_file, str) or not video_file.strip(): if not isinstance(video_file, str) or not video_file.strip():
@@ -289,3 +339,13 @@ def healthz():
"mongo_db_name": _mongo_db_name() or None, "mongo_db_name": _mongo_db_name() or None,
} }
@app.on_event("shutdown")
def _shutdown():
# Close the cached Mongo client cleanly.
try:
client = _mongo_client_cached()
client.close()
except Exception:
pass