clean-nodejs-mongodb
v0.0.3
Published
A robust MongoDB database connection module with circuit breaker, retry logic, and utilities for Node.js applications
Maintainers
Readme
Clean Node.js MongoDB
A robust MongoDB database connection module with circuit breaker pattern, retry logic, and comprehensive utilities for Node.js applications.
Features
- 🚀 Circuit Breaker Pattern: Automatic failure detection and recovery
- 🔄 Retry Logic: Exponential backoff with configurable retry attempts
- 📊 Connection Monitoring: Real-time metrics and health monitoring
- 🛡️ Type Safety: Full TypeScript support with comprehensive interfaces
- 📝 Advanced Logging: Structured logging with Winston integration
- 🏗️ Repository Pattern: Base repository class for CRUD operations
- 🔧 Flexible Configuration: Environment variables + explicit configuration
Installation
npm install clean-nodejs-mongodbQuick Start
Environment Variables (Recommended for Production)
# .env
DATABASE_URI=mongodb://localhost:27017/myapp
DATABASE_RETRY_ATTEMPTS=5
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=20import { DatabaseService, createDatabaseConfig } from 'clean-nodejs-mongodb';
// Initialize with environment variables
const dbService = await DatabaseService.init(createDatabaseConfig());Explicit Configuration (Recommended for Testing)
import { DatabaseService } from 'clean-nodejs-mongodb';
const config = {
uri: 'mongodb://localhost:27017/myapp',
retryAttempts: 5,
retryBaseDelay: 1000,
circuitBreakerFailureThreshold: 3,
connectionTimeout: 30000,
poolSize: { min: 2, max: 20 }
};
const dbService = await DatabaseService.init(config);Hybrid Approach (Environment + Overrides)
import { DatabaseService, createDatabaseConfig } from 'clean-nodejs-mongodb';
// Load from env vars but override specific settings
const dbService = await DatabaseService.init(createDatabaseConfig({
retryAttempts: 10, // Override retry attempts
uri: 'mongodb://prod-server:27017/prod-db' // Override URI
}));Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| uri | string | Required | MongoDB connection URI |
| retryAttempts | number | 3 | Number of retry attempts |
| retryBaseDelay | number | 1000 | Base delay between retries (ms) |
| retryMaxDelay | number | 30000 | Maximum delay between retries (ms) |
| circuitBreakerFailureThreshold | number | 5 | Failures before opening circuit |
| circuitBreakerRecoveryTimeout | number | 60000 | Recovery timeout (ms) |
| connectionTimeout | number | 30000 | Connection timeout (ms) |
| poolSize.min | number | 1 | Minimum pool size |
| poolSize.max | number | 10 | Maximum pool size |
Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| DATABASE_URI | mongodb://localhost:27017/defaultdb | MongoDB connection URI |
| MONGO_URI | - | Alternative MongoDB URI |
| DATABASE_RETRY_ATTEMPTS | 3 | Retry attempts |
| DATABASE_RETRY_BASE_DELAY | 1000 | Base retry delay |
| DATABASE_RETRY_MAX_DELAY | 30000 | Max retry delay |
| DATABASE_CIRCUIT_BREAKER_THRESHOLD | 5 | Circuit breaker threshold |
| DATABASE_CIRCUIT_BREAKER_RECOVERY | 60000 | Recovery timeout |
| DATABASE_CONNECTION_TIMEOUT | 30000 | Connection timeout |
| DATABASE_POOL_MIN | 1 | Min pool size |
| DATABASE_POOL_MAX | 10 | Max pool size |
Usage Examples
Basic Repository Usage
import { BaseRepository } from 'clean-nodejs-mongodb';
import { Schema, model, Document } from 'mongoose';
interface IUser extends Document {
name: string;
email: string;
createdAt: Date;
}
const userSchema = new Schema<IUser>({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
createdAt: { type: Date, default: Date.now }
});
const UserModel = model<IUser>('User', userSchema);
class UserRepository extends BaseRepository<IUser> {
constructor() {
super(UserModel);
}
async findByEmail(email: string): Promise<IUser | null> {
return this.model.findOne({ email }).exec();
}
}
// Usage
const userRepo = new UserRepository();
const user = await userRepo.create({ name: 'John Doe', email: '[email protected]' });Connection Management
import { DatabaseService, createDatabaseConfig } from 'clean-nodejs-mongodb';
// Initialize
const dbService = await DatabaseService.init(createDatabaseConfig());
// Check status
const status = dbService.connectionManager.getStatus();
console.log('Connected:', status.isConnected);
console.log('Circuit State:', status.circuitState);
// Force reconnect if needed
await dbService.connectionManager.forceReconnect();
// Graceful shutdown
await dbService.connectionManager.disconnect();Error Handling
import {
DatabaseConnectionError,
DatabaseCircuitBreakerError,
DatabaseQueryError
} from 'clean-nodejs-mongodb';
try {
const dbService = await DatabaseService.init(config);
} catch (error) {
if (error instanceof DatabaseConnectionError) {
console.error('Connection failed:', error.message);
} else if (error instanceof DatabaseCircuitBreakerError) {
console.error('Circuit breaker open:', error.message);
}
}Advanced Features
Circuit Breaker States
- CLOSED: Normal operation
- OPEN: Failing fast due to repeated failures
- HALF_OPEN: Testing if service recovered
Connection Monitoring
The module provides comprehensive metrics:
- Connection attempts and success/failure counts
- Average connection time
- Downtime tracking
- Circuit breaker state
Automatic Reconnection
The module automatically handles:
- Connection drops
- Network failures
- Server restarts
- Replica set failovers
Testing
import { DatabaseService } from 'clean-nodejs-mongodb';
// Use explicit config for predictable testing
const testConfig = {
uri: 'mongodb://localhost:27017/test',
retryAttempts: 1, // Faster tests
connectionTimeout: 5000
};
const dbService = await DatabaseService.init(testConfig);
// ... run tests
await dbService.connectionManager.disconnect();API Reference
DatabaseService
static init(config: DatabaseModuleConfig): Promise<DatabaseService>connectionManager: DatabaseConnectionManager
DatabaseConnectionManager
connect(): Promise<void>disconnect(): Promise<void>isConnected(): booleangetStatus(): ConnectionStatusforceReconnect(): Promise<void>resetCircuitBreaker(): void
BaseRepository
findById(id: string): Promise<T | null>findAll(filter?: any): Promise<T[]>create(data: Partial<T>): Promise<T>update(id: string, data: Partial<T>): Promise<T | null>delete(id: string): Promise<boolean>count(filter?: any): Promise<number>exists(id: string): Promise<boolean>
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see the LICENSE file for details.
Support
For issues and questions, please open an issue on GitHub.
