mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
50 lines
2.2 KiB
TypeScript
50 lines
2.2 KiB
TypeScript
import { sharedBlobCache, resultBlobCache } from "./blob-cache";
|
|
import { promises as fs } from "fs";
|
|
import { join } from "path";
|
|
import { tmpdir } from "os";
|
|
import { pruneTransformedCache } from "./transformed-cache";
|
|
import { createLogger } from "./logger";
|
|
|
|
const logger = createLogger("temporary-storage");
|
|
|
|
let nextCleanup = 0;
|
|
let cleanup: Promise<void> | undefined;
|
|
/** Jobs time out in minutes; an hour-old spool belongs to an interrupted process. */
|
|
export async function removeStaleTextSpools(directory = tmpdir(), now = Date.now()) {
|
|
const entries = await fs.opendir(directory);
|
|
for await (const entry of entries) {
|
|
if (!entry.isDirectory() || (!entry.name.startsWith("anonymous-text-") && !entry.name.startsWith("anonymous-zip-directory-"))) continue;
|
|
const path = join(directory, entry.name);
|
|
try {
|
|
const agePath = entry.name.startsWith("anonymous-zip-directory-") ? join(path, "central") : path;
|
|
if (now - (await fs.stat(agePath)).mtimeMs > 3600_000) await fs.rm(path, { recursive: true, force: true });
|
|
} catch { /* another process can finish cleanup first */ }
|
|
}
|
|
}
|
|
export function maintainTextSpools(force = false) {
|
|
if (cleanup) return cleanup;
|
|
if (!force && Date.now() < nextCleanup) return Promise.resolve();
|
|
nextCleanup = Date.now() + 60_000;
|
|
cleanup = removeStaleTextSpools().catch(() => {}).finally(() => { cleanup = undefined; });
|
|
return cleanup;
|
|
}
|
|
|
|
/** Recover on startup and continue while idle, without overlapping scans. */
|
|
export async function startTemporaryStorageMaintenance(intervalMs = 60_000) {
|
|
let running = false;
|
|
const run = async () => {
|
|
if (running) return;
|
|
running = true;
|
|
try {
|
|
const results = await Promise.allSettled([maintainTextSpools(true), pruneTransformedCache(), sharedBlobCache()?.maintain(), resultBlobCache()?.maintain()]);
|
|
for (const result of results) if (result.status === "rejected") {
|
|
logger.warn("temporary storage cleanup deferred", { message: (result.reason as Error).message });
|
|
}
|
|
} finally { running = false; }
|
|
};
|
|
await run();
|
|
const timer = setInterval(() => { void run(); }, intervalMs);
|
|
timer.unref();
|
|
return () => clearInterval(timer);
|
|
}
|