Snapshot Limit và Retention Policy
Giới thiệu
Trong bài này, chúng ta sẽ tìm hiểu về snapshot limit management và retention policy để kiểm soát số lượng snapshots/backups.
Snapshot Limit Check
Check Limit Before Create
typescript
export async function checkSnapshotLimitForManual(
serverId: string,
snapshotLimit: number,
location?: string
): Promise<void> {
// Normalize location
const normalizedLocation = normalizeLocationForCheck(location);
// Get actual snapshots from OpenStack
const snapshots = await listServerSnapshotsOpenStack({
serverId,
location: normalizedLocation,
limit: 1000,
});
// Filter by source (portal-manual or portal-auto)
const filteredImages = filterSnapshotsBySource(snapshots);
const totalCount = filteredImages.length;
// Check if limit exceeded
if (totalCount >= snapshotLimit) {
throw errorSnapshotLimitExceeded;
}
// Get backup schedule retain value
const retainValue = await getBackupScheduleRetain(serverId);
// Check if total + retain would exceed limit
const totalReserved = totalCount + retainValue;
if (totalReserved >= snapshotLimit) {
throw errorSnapshotLimitByScheduledBackup;
}
}Filter Snapshots by Source
Filter Function
typescript
export function filterSnapshotsBySource(snapshots: any[]): any[] {
if (!Array.isArray(snapshots)) {
return [];
}
return snapshots.filter((snapshot) => {
const source = snapshot?.source || '';
return source === 'portal-manual' || source === 'portal-auto';
});
}Filter Logic:
- Chỉ lấy snapshots có
source: 'portal-manual'hoặcsource: 'portal-auto' - Bỏ qua snapshots từ nguồn khác
Retention Policy
Retain Count
typescript
interface IBackupSchedule {
retain: number; // Number of backups to keep
// ...
}Cleanup Old Snapshots
typescript
// Cleanup old backups beyond retention limit
const toDelete = items.slice(schedule.retain);
for (const item of toDelete) {
try {
logger.info(`🗑️ Deleting old snapshot: ${item.name}`);
await deleteCloudServerSnapshotService({
id: Number(schedule.resourceId),
customerEmail: schedule.customerEmail,
snapshotImageId: item.id,
});
// Clean up metadata
await SnapshotMeta.deleteOne({
resourceType: 'cloud-server',
resourceId: String(schedule.resourceId),
providerSnapshotId: String(item.id),
});
} catch (e: any) {
logger.warn(`⚠️ Error deleting snapshot: ${e?.message}`);
}
}Limit Logic
Manual Snapshot
- Check: Total count < limit
- Error:
errorSnapshotLimitExceeded
Scheduled Backup
- Check: Total count + retain < limit
- Error:
errorSnapshotLimitByScheduledBackup - Reason: Cần đảm bảo có đủ slot cho retain backups
Best Practices
Check Limit Early
typescript
// ✅ DO: Check before creating
await checkSnapshotLimitForManual(serverId, snapshotLimit, location);
await createServerSnapshotOpenStack({ serverId, snapshotName, location });
// ❌ DON'T: Create first, check later
const result = await createServerSnapshotOpenStack({...});
if (tooManySnapshots) {
await delete(result.imageId); // Wasteful
}Sort by Date
typescript
// ✅ DO: Sort before slicing
items.sort((a, b) =>
new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
);
const toDelete = items.slice(schedule.retain);
// ❌ DON'T: Slice without sorting
const toDelete = items.slice(schedule.retain); // May delete wrong onesSummary
Key Points
Limit Check
- Check before creating
- Count actual snapshots from OpenStack
- Filter by source
Retention Policy
- Keep N latest backups
- Delete oldest first
- Clean up metadata
Error Handling
- Different errors for manual vs scheduled
- Clear error messages
Next Steps
Trong bài tiếp theo, chúng ta sẽ tìm hiểu về:
- Production Practices - Best practices cho production
Last Updated: 2025-01-25
Previous: 07. Multi-Location
Next: 09. Production Practices