6.9 KiB
MongoDB Handler
A singleton MongoDB handler with context manager support for MongoDB collections and automatic retry capabilities.
Features
- Singleton Pattern: Ensures only one instance of the MongoDB handler exists
- Context Manager: Automatically manages connection lifecycle
- Retry Capability: Automatically retries MongoDB operations on failure
- Connection Pooling: Configurable connection pooling
- Graceful Degradation: Handles connection failures without crashing
Usage
from Controllers.Mongo.database import mongo_handler
# Use the context manager to access a collection
with mongo_handler.collection("users") as users_collection:
# Perform operations on the collection
users_collection.insert_one({"username": "john", "email": "john@example.com"})
user = users_collection.find_one({"username": "john"})
# Connection is automatically closed when exiting the context
Configuration
MongoDB connection settings are configured via environment variables with the MONGO_ prefix:
MONGO_ENGINE: Database engine (e.g., "mongodb")MONGO_USER: MongoDB usernameMONGO_PASSWORD: MongoDB passwordMONGO_HOST: MongoDB hostMONGO_PORT: MongoDB portMONGO_DB: Database nameMONGO_AUTH_DB: Authentication database
Monitoring Connection Closure
To verify that MongoDB sessions are properly closed, you can implement one of the following approaches:
1. Add Logging to the __exit__ Method
def __exit__(self, exc_type, exc_val, exc_tb):
"""
Exit context, closing the connection.
"""
if self.client:
print(f"Closing MongoDB connection for collection: {self.collection_name}")
# Or use a proper logger
# logger.info(f"Closing MongoDB connection for collection: {self.collection_name}")
self.client.close()
self.client = None
self.collection = None
print(f"MongoDB connection closed successfully")
2. Add Connection Tracking
class MongoDBHandler:
# Add these to your class
_open_connections = 0
def get_connection_stats(self):
"""Return statistics about open connections"""
return {"open_connections": self._open_connections}
Then modify the CollectionContext class:
def __enter__(self):
try:
# Create a new client connection
self.client = MongoClient(self.db_handler.uri, **self.db_handler.client_options)
# Increment connection counter
self.db_handler._open_connections += 1
# Rest of your code...
def __exit__(self, exc_type, exc_val, exc_tb):
if self.client:
# Decrement connection counter
self.db_handler._open_connections -= 1
self.client.close()
self.client = None
self.collection = None
3. Use MongoDB's Built-in Monitoring
from pymongo import monitoring
class ConnectionCommandListener(monitoring.CommandListener):
def started(self, event):
print(f"Command {event.command_name} started on server {event.connection_id}")
def succeeded(self, event):
print(f"Command {event.command_name} succeeded in {event.duration_micros} microseconds")
def failed(self, event):
print(f"Command {event.command_name} failed in {event.duration_micros} microseconds")
# Register the listener
monitoring.register(ConnectionCommandListener())
4. Add a Test Function
def test_connection_closure():
"""Test that MongoDB connections are properly closed."""
print("\nTesting connection closure...")
# Record initial connection count (if you implemented the counter)
initial_count = mongo_handler.get_connection_stats()["open_connections"]
# Use multiple nested contexts
for i in range(5):
with mongo_handler.collection("test_collection") as collection:
# Do some simple operation
collection.find_one({})
# Check final connection count
final_count = mongo_handler.get_connection_stats()["open_connections"]
if final_count == initial_count:
print("Test passed: All connections were properly closed")
return True
else:
print(f"Test failed: {final_count - initial_count} connections remain open")
return False
5. Use MongoDB Server Logs
You can also check the MongoDB server logs to see connection events:
# Run this on your MongoDB server
tail -f /var/log/mongodb/mongod.log | grep "connection"
Best Practices
- Always use the context manager pattern to ensure connections are properly closed
- Keep operations within the context manager as concise as possible
- Handle exceptions within the context to prevent unexpected behavior
- Avoid nesting multiple context managers unnecessarily
- Use the retry decorator for operations that might fail due to transient issues
LXC Container Configuration
Authentication Issues
If you encounter authentication errors when connecting to the MongoDB container at 10.10.2.13:27017, you may need to update the container configuration:
-
Check MongoDB Authentication: Ensure the MongoDB container is configured with the correct authentication mechanism
-
Verify Network Configuration: Make sure the container network allows connections from your application
-
Update MongoDB Configuration:
- Edit the MongoDB configuration file in the container
- Ensure
bindIpis set correctly (e.g.,0.0.0.0to allow connections from any IP) - Check that authentication is enabled with the correct mechanism
-
User Permissions:
- Verify that the application user (
appuser) exists in the MongoDB instance - Ensure the user has the correct roles and permissions for the database
- Verify that the application user (
Example MongoDB Container Configuration
# Example docker-compose.yml configuration
services:
mongodb:
image: mongo:latest
container_name: mongodb
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
volumes:
- ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
ports:
- "27017:27017"
command: mongod --auth
// Example init-mongo.js
db.createUser({
user: 'appuser',
pwd: 'apppassword',
roles: [
{ role: 'readWrite', db: 'appdb' }
]
});
Troubleshooting
Common Issues
-
Authentication Failed:
- Verify username and password in environment variables
- Check that the user exists in the specified authentication database
- Ensure the user has appropriate permissions
-
Connection Refused:
- Verify the MongoDB host and port are correct
- Check network connectivity between application and MongoDB container
- Ensure MongoDB is running and accepting connections
-
Resource Leaks:
- Use the context manager pattern to ensure connections are properly closed
- Monitor connection pool size and active connections
- Implement proper error handling to close connections in case of exceptions