port-nimara-client-portal/server/utils/cleanup-manager.ts

161 lines
4.3 KiB
TypeScript

interface CleanupTask {
name: string;
cleanup: () => void | Promise<void>;
interval?: number;
}
class CleanupManager {
private static instance: CleanupManager;
private tasks: Map<string, CleanupTask> = new Map();
private intervals: Map<string, NodeJS.Timeout> = new Map();
private constructor() {
// Register default cleanup tasks
this.registerDefaultTasks();
}
static getInstance(): CleanupManager {
if (!CleanupManager.instance) {
CleanupManager.instance = new CleanupManager();
}
return CleanupManager.instance;
}
private registerDefaultTasks() {
// Clean up old temporary files
this.registerTask({
name: 'temp-files-cleanup',
cleanup: async () => {
console.log('[Cleanup] Running temporary files cleanup...');
// Implementation would go here
},
interval: 3600000 // Every hour
});
// Clean up expired cache entries
this.registerTask({
name: 'cache-cleanup',
cleanup: async () => {
console.log('[Cleanup] Running cache cleanup...');
// Implementation would go here
},
interval: 1800000 // Every 30 minutes
});
}
registerTask(task: CleanupTask) {
this.tasks.set(task.name, task);
if (task.interval) {
// Clear existing interval if any
const existingInterval = this.intervals.get(task.name);
if (existingInterval) {
clearInterval(existingInterval);
}
// Set up new interval
const interval = setInterval(async () => {
try {
await task.cleanup();
} catch (error) {
console.error(`[Cleanup] Task '${task.name}' failed:`, error);
}
}, task.interval);
this.intervals.set(task.name, interval);
}
}
async runTask(taskName: string) {
const task = this.tasks.get(taskName);
if (!task) {
throw new Error(`Cleanup task '${taskName}' not found`);
}
try {
await task.cleanup();
console.log(`[Cleanup] Task '${taskName}' completed successfully`);
} catch (error) {
console.error(`[Cleanup] Task '${taskName}' failed:`, error);
throw error;
}
}
async runAllTasks() {
console.log('[Cleanup] Running all cleanup tasks...');
const results: { task: string; success: boolean; error?: any }[] = [];
for (const [name, task] of this.tasks) {
try {
await task.cleanup();
results.push({ task: name, success: true });
} catch (error) {
results.push({ task: name, success: false, error });
}
}
return results;
}
stopAllIntervals() {
for (const [name, interval] of this.intervals) {
clearInterval(interval);
console.log(`[Cleanup] Stopped interval for task '${name}'`);
}
this.intervals.clear();
}
}
export const cleanupManager = CleanupManager.getInstance();
// Utility functions for common cleanup operations
export const cleanupUtils = {
// Clean up old files in a directory
async cleanupOldFiles(directory: string, maxAgeMs: number) {
// Implementation would check file ages and remove old ones
console.log(`[Cleanup] Would clean files older than ${maxAgeMs}ms in ${directory}`);
},
// Clean up unused stream handles
cleanupStreams(streams: any[]) {
streams.forEach(stream => {
if (stream && typeof stream.destroy === 'function') {
stream.destroy();
}
});
},
// Clean up IMAP connections
cleanupIMAPConnections(connections: any[]) {
connections.forEach(conn => {
try {
if (conn && typeof conn.end === 'function') {
conn.end();
}
} catch (error) {
console.error('[Cleanup] Failed to close IMAP connection:', error);
}
});
},
// Memory-efficient array processing
async processInBatches<T, R>(
items: T[],
batchSize: number,
processor: (batch: T[]) => Promise<R[]>
): Promise<R[]> {
const results: R[] = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const batchResults = await processor(batch);
results.push(...batchResults);
// Allow garbage collection between batches
await new Promise(resolve => setImmediate(resolve));
}
return results;
}
};