Spaces:
Runtime error
Runtime error
| # db/mongoDB.py | |
| import logging | |
| from typing import Optional | |
| from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase, AsyncIOMotorCollection | |
| from pymongo.errors import ConnectionFailure, ConfigurationError | |
| import config # Import từ file config tập trung | |
| logger = logging.getLogger(__name__) | |
| class MongoDatabase: | |
| """ | |
| Một lớp singleton để quản lý kết nối và các collection của MongoDB. | |
| Điều này đảm bảo chúng ta chỉ có một kết nối duy nhất trong toàn bộ ứng dụng. | |
| """ | |
| client: Optional[AsyncIOMotorClient] = None | |
| db: Optional[AsyncIOMotorDatabase] = None | |
| # Khai báo các collection bạn sẽ sử dụng | |
| users: Optional[AsyncIOMotorCollection] = None | |
| token_blacklist: Optional[AsyncIOMotorCollection] = None | |
| conversations: Optional[AsyncIOMotorCollection] = None | |
| processed_documents: Optional[AsyncIOMotorCollection] = None | |
| # Tạo một instance duy nhất để import và sử dụng trong toàn bộ ứng dụng | |
| mongo_db = MongoDatabase() | |
| async def connect_to_mongo(): | |
| """ | |
| Hàm khởi tạo kết nối đến MongoDB Atlas và gán vào object mongo_db. | |
| Hàm này sẽ được gọi từ lifespan của FastAPI. | |
| """ | |
| if mongo_db.client: | |
| logger.info("✅ MongoDB connection already established.") | |
| return | |
| logger.info(f"🔸 Connecting to MongoDB Atlas...") | |
| if not config.MONGODB_CLOUD_URI or not config.DB_NAME: | |
| logger.error("❌ MONGODB_CLOUD_URI hoặc DB_NAME chưa được thiết lập trong biến môi trường.") | |
| raise ConfigurationError("MONGODB_CLOUD_URI and DB_NAME must be set.") | |
| try: | |
| # 1. Khởi tạo client bất đồng bộ | |
| mongo_db.client = AsyncIOMotorClient( | |
| config.MONGODB_CLOUD_URI, | |
| serverSelectionTimeoutMS=30000 # Thời gian chờ kết nối là 5 giây | |
| ) | |
| # 2. Kiểm tra kết nối một cách rõ ràng | |
| await mongo_db.client.admin.command('ping') | |
| # 3. Gán các đối tượng database và collection | |
| mongo_db.db = mongo_db.client[config.DB_NAME] | |
| mongo_db.users = mongo_db.db["users"] | |
| mongo_db.token_blacklist = mongo_db.db["token_blacklist"] | |
| mongo_db.conversations = mongo_db.db["conversations"] | |
| mongo_db.processed_documents = mongo_db.db["processed_documents"] | |
| # 4. Tạo TTL index một cách an toàn | |
| # Lấy danh sách index hiện có | |
| index_info = await mongo_db.token_blacklist.index_information() | |
| if "expires_at_1" not in index_info: | |
| # Chỉ tạo index nếu nó chưa tồn tại | |
| await mongo_db.token_blacklist.create_index("expires_at", expireAfterSeconds=0) | |
| logger.info("🔸 Successfully created TTL index for 'expires_at' in 'token_blacklist'.") | |
| logger.info("✅ MongoDB connection successful and collections are ready.") | |
| except ConnectionFailure as e: | |
| logger.error(f"❌ Failed to connect to MongoDB: Connection Failure. Check your URI and network access rules in Atlas. Error: {e}", exc_info=True) | |
| raise e | |
| except ConfigurationError as e: | |
| logger.error(f"❌ Failed to connect to MongoDB: Configuration Error. Check your connection string format. Error: {e}", exc_info=True) | |
| raise e | |
| except Exception as e: | |
| logger.error(f"❌ An unexpected error occurred while connecting to MongoDB: {e}", exc_info=True) | |
| raise e | |
| async def close_mongo_connection(): | |
| """Hàm đóng kết nối MongoDB khi ứng dụng tắt.""" | |
| if mongo_db.client: | |
| mongo_db.client.close() | |
| logger.info("✅ MongoDB connection closed.") |