Skip to content

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ặc source: '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 ones

Summary

Key Points

  1. Limit Check

    • Check before creating
    • Count actual snapshots from OpenStack
    • Filter by source
  2. Retention Policy

    • Keep N latest backups
    • Delete oldest first
    • Clean up metadata
  3. 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ề:


Last Updated: 2025-01-25
Previous: 07. Multi-Location
Next: 09. Production Practices

Internal documentation for iNET Portal