Controllers added updated implementations and tests awaits
This commit is contained in:
24
Controllers/Mongo/config.py
Normal file
24
Controllers/Mongo/config.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Configs(BaseSettings):
|
||||
"""
|
||||
MongoDB configuration settings.
|
||||
"""
|
||||
|
||||
USER: str = ""
|
||||
PASSWORD: str = ""
|
||||
HOST: str = ""
|
||||
PORT: int = 0
|
||||
DB: str = ""
|
||||
ENGINE: str = ""
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""Generate the database URL."""
|
||||
return f"{self.ENGINE}://{self.USER}:{self.PASSWORD}@{self.HOST}:{self.PORT}/{self.DB}?retryWrites=true&w=majority"
|
||||
|
||||
model_config = SettingsConfigDict(env_prefix="MONGO_")
|
||||
|
||||
|
||||
mongo_configs = Configs() # singleton instance of the MONGODB configuration settings
|
||||
208
Controllers/Mongo/database.py
Normal file
208
Controllers/Mongo/database.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import time
|
||||
import functools
|
||||
|
||||
from pymongo import MongoClient
|
||||
from pymongo.errors import PyMongoError
|
||||
from config import mongo_configs
|
||||
|
||||
|
||||
def retry_operation(max_attempts=3, delay=1.0, backoff=2.0, exceptions=(PyMongoError,)):
|
||||
"""
|
||||
Decorator for retrying MongoDB operations with exponential backoff.
|
||||
|
||||
Args:
|
||||
max_attempts: Maximum number of retry attempts
|
||||
delay: Initial delay between retries in seconds
|
||||
backoff: Multiplier for delay after each retry
|
||||
exceptions: Tuple of exceptions to catch and retry
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
mtries, mdelay = max_attempts, delay
|
||||
while mtries > 1:
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except exceptions as e:
|
||||
time.sleep(mdelay)
|
||||
mtries -= 1
|
||||
mdelay *= backoff
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
class MongoDBConfig:
|
||||
"""
|
||||
Configuration class for MongoDB connection settings.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
uri: str = "mongodb://localhost:27017/",
|
||||
max_pool_size: int = 50,
|
||||
min_pool_size: int = 10,
|
||||
max_idle_time_ms: int = 30000,
|
||||
wait_queue_timeout_ms: int = 2000,
|
||||
server_selection_timeout_ms: int = 5000,
|
||||
**additional_options,
|
||||
):
|
||||
"""
|
||||
Initialize MongoDB configuration.
|
||||
"""
|
||||
self.uri = uri
|
||||
self.client_options = {
|
||||
"maxPoolSize": max_pool_size,
|
||||
"minPoolSize": min_pool_size,
|
||||
"maxIdleTimeMS": max_idle_time_ms,
|
||||
"waitQueueTimeoutMS": wait_queue_timeout_ms,
|
||||
"serverSelectionTimeoutMS": server_selection_timeout_ms,
|
||||
**additional_options,
|
||||
}
|
||||
|
||||
|
||||
class MongoDBHandler(MongoDBConfig):
|
||||
"""
|
||||
A MongoDB handler that provides context manager access to specific collections
|
||||
with automatic retry capability.
|
||||
"""
|
||||
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
Implement singleton pattern for the handler.
|
||||
"""
|
||||
if cls._instance is None:
|
||||
cls._instance = super(MongoDBHandler, cls).__new__(cls)
|
||||
cls._instance._initialized = False
|
||||
return cls._instance
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
uri: str,
|
||||
max_pool_size: int = 50,
|
||||
min_pool_size: int = 10,
|
||||
max_idle_time_ms: int = 30000,
|
||||
wait_queue_timeout_ms: int = 2000,
|
||||
server_selection_timeout_ms: int = 5000,
|
||||
**additional_options,
|
||||
):
|
||||
"""
|
||||
Initialize the MongoDB handler (only happens once due to singleton).
|
||||
"""
|
||||
# Only initialize once
|
||||
if not hasattr(self, "_initialized") or not self._initialized:
|
||||
super().__init__(
|
||||
uri=uri,
|
||||
max_pool_size=max_pool_size,
|
||||
min_pool_size=min_pool_size,
|
||||
max_idle_time_ms=max_idle_time_ms,
|
||||
wait_queue_timeout_ms=wait_queue_timeout_ms,
|
||||
server_selection_timeout_ms=server_selection_timeout_ms,
|
||||
**additional_options,
|
||||
)
|
||||
self._initialized = True
|
||||
|
||||
def collection(self, collection_name: str):
|
||||
"""
|
||||
Get a context manager for a specific collection.
|
||||
|
||||
Args:
|
||||
collection_name: Name of the collection to access
|
||||
|
||||
Returns:
|
||||
A context manager for the specified collection
|
||||
"""
|
||||
return CollectionContext(self, collection_name)
|
||||
|
||||
|
||||
class CollectionContext:
|
||||
"""
|
||||
Context manager for MongoDB collections with automatic retry capability.
|
||||
"""
|
||||
|
||||
def __init__(self, db_handler: MongoDBHandler, collection_name: str):
|
||||
"""
|
||||
Initialize collection context.
|
||||
|
||||
Args:
|
||||
db_handler: Reference to the MongoDB handler
|
||||
collection_name: Name of the collection to access
|
||||
"""
|
||||
self.db_handler = db_handler
|
||||
self.collection_name = collection_name
|
||||
self.client = None
|
||||
self.collection = None
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
Enter context, establishing a new connection.
|
||||
|
||||
Returns:
|
||||
The MongoDB collection object with retry capabilities
|
||||
"""
|
||||
try:
|
||||
# Create a new client connection
|
||||
self.client = MongoClient(
|
||||
self.db_handler.uri, **self.db_handler.client_options
|
||||
)
|
||||
self.collection = self.client.get_database()[self.collection_name]
|
||||
|
||||
# Enhance collection methods with retry capabilities
|
||||
self._add_retry_capabilities()
|
||||
|
||||
return self.collection
|
||||
except Exception as e:
|
||||
if self.client:
|
||||
self.client.close()
|
||||
raise
|
||||
|
||||
def _add_retry_capabilities(self):
|
||||
"""
|
||||
Add retry capabilities to collection methods.
|
||||
"""
|
||||
# Store original methods
|
||||
original_insert_one = self.collection.insert_one
|
||||
original_insert_many = self.collection.insert_many
|
||||
original_find_one = self.collection.find_one
|
||||
original_find = self.collection.find
|
||||
original_update_one = self.collection.update_one
|
||||
original_update_many = self.collection.update_many
|
||||
original_delete_one = self.collection.delete_one
|
||||
original_delete_many = self.collection.delete_many
|
||||
original_replace_one = self.collection.replace_one
|
||||
original_count_documents = self.collection.count_documents
|
||||
|
||||
# Add retry capabilities to methods
|
||||
self.collection.insert_one = retry_operation()(original_insert_one)
|
||||
self.collection.insert_many = retry_operation()(original_insert_many)
|
||||
self.collection.find_one = retry_operation()(original_find_one)
|
||||
self.collection.find = retry_operation()(original_find)
|
||||
self.collection.update_one = retry_operation()(original_update_one)
|
||||
self.collection.update_many = retry_operation()(original_update_many)
|
||||
self.collection.delete_one = retry_operation()(original_delete_one)
|
||||
self.collection.delete_many = retry_operation()(original_delete_many)
|
||||
self.collection.replace_one = retry_operation()(original_replace_one)
|
||||
self.collection.count_documents = retry_operation()(original_count_documents)
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
Exit context, closing the connection.
|
||||
"""
|
||||
if self.client:
|
||||
self.client.close()
|
||||
self.client = None
|
||||
self.collection = None
|
||||
|
||||
|
||||
mongo_handler = MongoDBHandler(
|
||||
uri=mongo_configs.url,
|
||||
db_name=mongo_configs.DB,
|
||||
max_pool_size=100,
|
||||
min_pool_size=20,
|
||||
max_idle_time_ms=60000,
|
||||
)
|
||||
17
Controllers/Mongo/implementations.py
Normal file
17
Controllers/Mongo/implementations.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Initialize the MongoDB handler with your configuration
|
||||
from Controllers.Mongo.database import mongo_handler
|
||||
|
||||
|
||||
# Use the collection with automatic retry capabilities
|
||||
with mongo_handler.collection("users") as users_collection:
|
||||
|
||||
# These operations will automatically retry on failure
|
||||
users_collection.insert_one({"username": "john", "email": "john@example.com"})
|
||||
|
||||
# Find operations also have retry capabilities
|
||||
user = users_collection.find_one({"username": "john"})
|
||||
|
||||
# Update operations will retry if they encounter transient errors
|
||||
users_collection.update_one(
|
||||
{"username": "john"}, {"$set": {"last_login": "2025-03-31"}}
|
||||
)
|
||||
Reference in New Issue
Block a user