feat: add worker threads, persistent Python sidecar, graceful shutdown, and architectural improvements

- Graceful shutdown: SIGTERM/SIGINT handlers drain HTTP, stop workers, close DB
- Thumbnail caching: disk-cached thumbnails with immutable Cache-Control headers
- Worker thread pool: Piscina offloads Sharp processing off the main event loop
- Persistent Python dispatcher: pre-imports ML libraries, eliminates cold-start latency
- Tool page registry: declarative tool-to-component mapping replaces 750-line switch
- File store cleanup: remove dead derived fields, stable files array reference
- Job persistence: progress written to SQLite jobs table, stale jobs recovered on startup
This commit is contained in:
Siddharth Kumar Sah
2026-03-29 17:23:41 +08:00
parent 88729e255d
commit 1cbdfa1590
20 changed files with 1575 additions and 530 deletions
+37 -1
View File
@@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import { mkdir, unlink, writeFile } from "node:fs/promises";
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
import { extname, join } from "node:path";
import { env } from "../config.js";
@@ -49,3 +49,39 @@ export async function deleteStoredFile(storedName: string): Promise<void> {
export function getStoredFilePath(storedName: string): string {
return join(env.FILES_STORAGE_PATH, storedName);
}
// ── Thumbnail cache ──────────────────────────────────────────────────
const THUMB_DIR = ".thumbs";
let thumbDirReady = false;
async function ensureThumbDir(): Promise<void> {
if (thumbDirReady) return;
await mkdir(join(env.FILES_STORAGE_PATH, THUMB_DIR), { recursive: true });
thumbDirReady = true;
}
function thumbPath(storedName: string): string {
return join(env.FILES_STORAGE_PATH, THUMB_DIR, `${storedName}.thumb.jpg`);
}
export async function getCachedThumbnail(storedName: string): Promise<Buffer | null> {
try {
return await readFile(thumbPath(storedName));
} catch {
return null;
}
}
export async function saveThumbnail(storedName: string, buffer: Buffer): Promise<void> {
await ensureThumbDir();
await writeFile(thumbPath(storedName), buffer);
}
export async function deleteThumbnail(storedName: string): Promise<void> {
try {
await unlink(thumbPath(storedName));
} catch {
// Thumbnail may not exist
}
}