Managing Maintenance Windows Without Business Impact
Database maintenance is necessary for updates, optimizations, and configuration changes. This post covers strategies for scheduling maintenance windows and performing zero-downtime operations to minimize business impact.
🎯 Understanding Maintenance Windows
Types of Maintenance
- Planned Maintenance: Scheduled updates, optimizations
- Emergency Maintenance: Critical security patches, bug fixes
- Routine Maintenance: Regular backups, health checks
Maintenance Window Goals
- Minimize downtime: Reduce service interruption
- Schedule appropriately: Choose low-traffic periods
- Communicate clearly: Notify stakeholders
- Plan thoroughly: Prepare rollback procedures
- Monitor closely: Watch for issues
📅 Planning Maintenance Windows
Identify Low-Traffic Periods
// src/services/analytics.service.ts
export class AnalyticsService {
async getTrafficPatterns() {
// Analyze traffic by hour/day
const patterns = await prisma.$queryRaw`
SELECT
HOUR(created_at) as hour,
DAYNAME(created_at) as day,
COUNT(*) as requests
FROM sales
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY hour, day
ORDER BY requests ASC
`;
return patterns;
}
async getRecommendedMaintenanceWindow() {
const patterns = await this.getTrafficPatterns();
// Find lowest traffic period
return patterns[0];
}
}
Maintenance Window Schedule
Recommended Times:
- Weekend nights: 2 AM - 4 AM Saturday/Sunday
- Weekday nights: 2 AM - 4 AM (lowest traffic)
- Holiday periods: Extended maintenance windows
🔄 Zero-Downtime Strategies
1. Blue-Green Deployment
Maintain two identical database environments:
# Current production (blue)
DATABASE_BLUE="db_prod_blue"
# New production (green)
DATABASE_GREEN="db_prod_green"
# Switch traffic
# 1. Provision green with updates
# 2. Sync data
# 3. Switch application to green
# 4. Monitor
# 5. Decommission blue
2. Read Replicas
Use read replicas to handle traffic during maintenance:
-- Create read replica
CREATE DATABASE db_replica;
-- Configure replication
CHANGE MASTER TO
MASTER_HOST='primary_db',
MASTER_USER='replica_user',
MASTER_PASSWORD='replica_pass',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=1234;
START SLAVE;
3. Connection Pooling
Configure connection pooling to handle brief interruptions:
// src/config/database.ts
export const prisma = new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL
}
},
// Connection pool configuration
__internal: {
engine: {
connectTimeout: 10000,
pool: {
min: 2,
max: 10
}
}
}
});
🛠️ Maintenance Operations
Configuration Changes
Non-restart changes:
-- Changes that don't require restart
SET GLOBAL max_connections = 500;
SET GLOBAL query_cache_size = 268435456;
SET GLOBAL slow_query_log = 'ON';
Restart-required changes:
-- Changes requiring restart
-- Update my.cnf, then schedule restart during maintenance window
[mysqld]
innodb_buffer_pool_size = 4G
innodb_log_file_size = 256M
Version Upgrades
Upgrade Process:
- Backup: Full backup before upgrade
- Test: Test upgrade in staging
- Schedule: Plan maintenance window
- Upgrade: Execute upgrade
- Verify: Test functionality
- Monitor: Watch for issues
#!/bin/bash
# upgrade-database.sh
DB_ID=$1
TARGET_VERSION=$2
echo "Starting database upgrade..."
# Step 1: Create backup
echo "Creating backup..."
# (Trigger backup via UI or CLI tool)
BACKUP_ID="backup_123"
# Step 2: Wait for backup
echo "Waiting for backup to complete..."
# ... wait logic ...
# Step 3: Start upgrade
echo "Starting upgrade to $TARGET_VERSION..."
# (Trigger upgrade via UI or CLI tool)
# Step 4: Monitor upgrade
echo "Monitoring upgrade progress..."
# ... monitoring logic ...
echo "Upgrade completed!"
Schema Migrations
Safe Migration Strategy:
// src/migrations/safe-migration.ts
export async function safeMigration() {
// Step 1: Add new column as nullable
await prisma.$executeRaw`
ALTER TABLE customers
ADD COLUMN new_field VARCHAR(255) NULL
`;
// Step 2: Backfill data (can run during business hours)
await prisma.$executeRaw`
UPDATE customers
SET new_field = 'default_value'
WHERE new_field IS NULL
`;
// Step 3: Make column NOT NULL (requires brief lock)
await prisma.$executeRaw`
ALTER TABLE customers
MODIFY COLUMN new_field VARCHAR(255) NOT NULL
`;
}
📊 Maintenance Window Management
Schedule Maintenance
# Visual example of maintenance scheduling
# (Imagine a beautiful UI here)
Maintenance Status
// src/services/maintenance.service.ts
export class MaintenanceService {
async getScheduledMaintenance() {
// Fetch maintenance status from platform
const response = await fetch(
`https://api.example.com/v1/databases/${dbId}/maintenance`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
return response.json();
}
async notifyUsers(maintenance: MaintenanceWindow) {
// Send notifications to users
await emailService.send({
subject: `Scheduled Maintenance: ${maintenance.description}`,
body: `Database will be unavailable from ${maintenance.start} to ${maintenance.end}`
});
}
}
🔔 Pre-Maintenance Checklist
Before Maintenance
- Backup created and verified
- Maintenance window scheduled
- Stakeholders notified
- Rollback plan prepared
- Monitoring enhanced
- Support team on standby
- Documentation updated
During Maintenance
- Monitor application health
- Watch for errors
- Track progress
- Document any issues
- Communicate status
After Maintenance
- Verify functionality
- Check performance metrics
- Review logs
- Update documentation
- Notify completion
🧪 Testing Maintenance Procedures
Staging Environment
#!/bin/bash
# test-maintenance.sh
# Run maintenance on staging first
STAGING_DB="db_staging"
PROD_DB="db_production"
echo "Testing maintenance on staging..."
# Perform maintenance on staging
./perform-maintenance.sh $STAGING_DB
# Verify staging
./verify-database.sh $STAGING_DB
if [ $? -eq 0 ]; then
echo "Staging test passed, proceeding to production..."
./perform-maintenance.sh $PROD_DB
else
echo "Staging test failed, aborting production maintenance"
exit 1
fi
📈 Monitoring During Maintenance
Enhanced Monitoring
// src/middleware/maintenance-monitor.ts
export function maintenanceMonitor(req: Request, res: Response, next: NextFunction) {
const isMaintenance = process.env.MAINTENANCE_MODE === 'true';
if (isMaintenance) {
// Log all requests during maintenance
console.log(`Maintenance mode: ${req.method} ${req.path}`);
// Return maintenance response for non-critical endpoints
if (!isCriticalEndpoint(req.path)) {
return res.status(503).json({
status: 'maintenance',
message: 'Service temporarily unavailable for maintenance'
});
}
}
next();
}
Health Checks
// src/routes/health.routes.ts
router.get('/health/maintenance', async (req, res) => {
const maintenance = await maintenanceService.getActiveMaintenance();
if (maintenance) {
res.json({
status: 'maintenance',
maintenance: {
start: maintenance.scheduled_at,
estimated_end: maintenance.estimated_end,
description: maintenance.description
}
});
} else {
res.json({ status: 'operational' });
}
});
🔄 Rollback Procedures
Automated Rollback
#!/bin/bash
# rollback-maintenance.sh
DB_ID=$1
BACKUP_ID=$2
echo "Rolling back maintenance..."
# Visual example of maintenance scheduling
# (Imagine a beautiful UI here)
echo "Rollback initiated"
Manual Rollback Steps
- Stop application traffic (if needed)
- Restore from backup
- Verify data integrity
- Resume traffic
- Investigate issue
- Plan fix
✅ Maintenance Window Best Practices
- Plan ahead: Schedule well in advance
- Communicate: Notify all stakeholders
- Test first: Always test in staging
- Backup: Always backup before changes
- Monitor: Enhanced monitoring during maintenance
- Document: Document all procedures
- Review: Post-maintenance review
🎯 Filess.io Maintenance Features
Scheduled Maintenance
# Visual example of maintenance history
# (Imagine a beautiful UI here)
With proper planning and execution, maintenance windows can be managed with minimal business impact, ensuring your database remains up-to-date and optimized.