Files
aigen/server/utils/studio2/cleanup.ts
T

51 lines
2.4 KiB
TypeScript

import { scopedFile } from '~/shared/studio2/contracts.mjs';
import { sharedGpuHeaders, withSharedGpuStart } from '../sharedGpu';
import { records, saveRecord } from './store';
/** Called only after the output and handoff frame are durably saved. */
export async function purge(r: any, includeCurrent = true) {
const config = useRuntimeConfig(), prefix = String(config.comfyFilenamePrefix);
const pending = r.cleanupPending || [];
const files = [...pending, ...(includeCurrent ? r.files || [] : [])].filter((file, i, all) => all.findIndex(f => f.filename === file.filename && f.subfolder === file.subfolder && f.type === file.type) === i);
r.cleanupPending = files;
r.purgeResult = 'Cleanup pending';
saveRecord(r);
if (!files.length) return;
try {
if (files.some(file => !scopedFile(file, prefix))) throw new Error('Cleanup manifest is outside this studio');
for (let offset = 0; offset < files.length; offset += 100) {
const batch = files.slice(offset, offset + 100);
const response = await fetch(String(config.comfyControlUrl).replace(/\/$/, '') + '/studio2/purge', {
method: 'POST', headers: { 'Content-Type': 'application/json', ...sharedGpuHeaders() },
body: JSON.stringify({ prefix, files: batch }), signal: AbortSignal.timeout(12000)
});
const result = await response.json() as any;
if (!response.ok || !result.ok || result.cleared !== batch.length) throw new Error(`Local cleanup was not confirmed (${response.status})`);
r.cleanupPending = files.slice(offset + batch.length);
saveRecord(r);
}
r.purgeResult = 'Cleared input + output';
r.cleanupError = '';
} catch (error: any) {
r.cleanupError = error.message || 'Local cleanup unavailable';
console.warn('[Studio 2 cleanup]', r.id, r.cleanupError);
}
saveRecord(r);
}
let retrying = false;
export async function retryCleanup() {
if (retrying) return;
retrying = true;
try {
const pending = records().filter(r => r.cleanupPending?.length && ['complete', 'failed', 'cancelled'].includes(r.state));
if (!pending.length) return;
await withSharedGpuStart(async () => {
for (const r of pending) {
// Never add a later failed shot's unsaved files to the saved cleanup manifest.
await purge(r, false);
}
}, async () => {});
} finally { retrying = false; }
}