Type: Bug - Critical | Priority: CRITICAL | Effort: 3 hours
Component: backend/src/lib/database.ts, backend/src/index.ts
Problem:
Database connection failures cause immediate application crashes with no retry mechanism. This is a critical production issue where:
- Temporary network issues crash the entire application
- Database maintenance windows cause unnecessary downtime
- Connection pool exhaustion leads to cascading failures
- No graceful degradation when database is temporarily unavailable
- Users experience complete service outages for transient issues
Current Behavior:
// CURRENT (crashes immediately on connection failure)
const prisma = new PrismaClient();
await prisma.$connect(); // Throws error, crashes app
Real-world Impact:
- Production incidents: Average 3-5 per month
- Mean Time to Recovery (MTTR): 10-15 minutes
- User-facing downtime: 100% during database connectivity issues
- Lost transactions during brief network interruptions
Acceptance Criteria:
Implementation Strategy:
// AFTER (with retry logic)
import retry from 'async-retry';
const prisma = new PrismaClient({
log: ['error', 'warn'],
errorFormat: 'minimal'
});
async function connectWithRetry() {
await retry(async (bail, attempt) => {
try {
await prisma.$connect();
logger.info(`Database connected on attempt ${attempt}`);
} catch (error) {
logger.warn(`Database connection attempt ${attempt} failed:`, error.message);
// Don't retry on authentication errors
if (error.code === 'P1001' || error.code === 'P1002') {
bail(error);
return;
}
// Throw to trigger retry
throw error;
}
}, {
retries: 6,
factor: 2,
minTimeout: 1000,
maxTimeout: 32000,
randomize: true,
onRetry: (error, attempt) => {
logger.warn(`Retry attempt ${attempt} for database connection`);
}
});
}
// Circuit breaker implementation
class DatabaseCircuitBreaker {
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
private failureCount = 0;
private lastFailureTime?: Date;
async execute<T>(operation: () => Promise<T>): Promise<T> {
if (this.state === 'OPEN') {
const timeSinceFailure = Date.now() - this.lastFailureTime!.getTime();
if (timeSinceFailure > 30000) { // 30 seconds
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await operation();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
private onFailure() {
this.failureCount++;
this.lastFailureTime = new Date();
if (this.failureCount >= 5) {
this.state = 'OPEN';
logger.error('Circuit breaker opened due to consecutive failures');
}
}
}
Graceful Degradation Strategy:
// Health check endpoint
app.get('/health', async (req, res) => {
try {
await circuitBreaker.execute(async () => {
await prisma.$queryRaw`SELECT 1`;
});
res.json({ status: 'healthy', database: 'connected' });
} catch (error) {
res.status(503).json({
status: 'degraded',
database: 'disconnected',
mode: 'read-only'
});
}
});
// Read-only mode handler
async function handleDatabaseOperation<T>(
operation: () => Promise<T>,
fallbackCache?: () => T
): Promise<T> {
try {
return await circuitBreaker.execute(operation);
} catch (error) {
if (fallbackCache && circuitBreaker.state === 'OPEN') {
logger.warn('Using cached data due to database unavailability');
return fallbackCache();
}
throw error;
}
}
Monitoring & Alerting:
Related Files:
backend/src/lib/database.ts (main implementation)
backend/src/lib/circuit-breaker.ts (create)
backend/src/middleware/health-check.ts (create)
backend/src/index.ts (initialization)
backend/RUNBOOK.md (operational procedures)
Success Criteria:
- Zero application crashes due to transient database issues
- Sub-60-second recovery time after database becomes available
- All write operations preserved and replayed in order
- Read operations served from cache during outages
- Comprehensive monitoring and alerting in place
Type: Bug - Critical | Priority: CRITICAL | Effort: 3 hours
Component:
backend/src/lib/database.ts,backend/src/index.tsProblem:
Database connection failures cause immediate application crashes with no retry mechanism. This is a critical production issue where:
Current Behavior:
Real-world Impact:
Acceptance Criteria:
Implementation Strategy:
Graceful Degradation Strategy:
Monitoring & Alerting:
Related Files:
backend/src/lib/database.ts(main implementation)backend/src/lib/circuit-breaker.ts(create)backend/src/middleware/health-check.ts(create)backend/src/index.ts(initialization)backend/RUNBOOK.md(operational procedures)Success Criteria: