mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: resolve 6 production Sentry errors
- Prevent @fastify/static double-registration crash via decorateReply guard - Fix non-ASCII filename header encoding (X-Output-Filename + RFC 5987 Content-Disposition) - Add EACCES error handling to all startup mkdir calls with actionable messages - Add WAL autocheckpoint and journal size limit to prevent unbounded SQLite growth - Fix Python sidecar EPIPE handling to reject pending requests and trigger restart - Ensure Docker entrypoint creates all subdirectories before chown
This commit is contained in:
@@ -44,8 +44,17 @@ export function shouldRunStartupCleanup(): boolean {
|
||||
}
|
||||
|
||||
export function startCleanupCron(): { stop: () => void } {
|
||||
// Ensure workspace directory exists
|
||||
mkdirSync(env.WORKSPACE_PATH, { recursive: true });
|
||||
try {
|
||||
mkdirSync(env.WORKSPACE_PATH, { recursive: true });
|
||||
} catch (err: unknown) {
|
||||
const code = (err as NodeJS.ErrnoException).code;
|
||||
if (code === "EACCES") {
|
||||
console.error(
|
||||
`WARNING: Cannot create workspace directory "${env.WORKSPACE_PATH}". Check volume permissions (PUID/PGID).`,
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
const intervalMs = env.CLEANUP_INTERVAL_MINUTES * 60 * 1000;
|
||||
|
||||
|
||||
@@ -41,9 +41,20 @@ export function getManifestPath(): string {
|
||||
|
||||
export function ensureAiDirs(): void {
|
||||
if (!isDockerEnvironment()) return;
|
||||
mkdirSync(join(AI_DIR, "venv"), { recursive: true });
|
||||
mkdirSync(MODELS_DIR, { recursive: true });
|
||||
mkdirSync(join(AI_DIR, "pip-cache"), { recursive: true });
|
||||
try {
|
||||
mkdirSync(join(AI_DIR, "venv"), { recursive: true });
|
||||
mkdirSync(MODELS_DIR, { recursive: true });
|
||||
mkdirSync(join(AI_DIR, "pip-cache"), { recursive: true });
|
||||
} catch (err: unknown) {
|
||||
const code = (err as NodeJS.ErrnoException).code;
|
||||
if (code === "EACCES") {
|
||||
console.error(
|
||||
`WARNING: Cannot create AI directories under "${AI_DIR}". AI features will be unavailable. Check volume permissions (PUID/PGID).`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Docker detection ────────────────────────────────────────────────────
|
||||
|
||||
@@ -115,7 +115,14 @@ let thumbDirReady = false;
|
||||
|
||||
async function ensureThumbDir(): Promise<void> {
|
||||
if (thumbDirReady) return;
|
||||
await mkdir(join(env.FILES_STORAGE_PATH, THUMB_DIR), { recursive: true });
|
||||
try {
|
||||
await mkdir(join(env.FILES_STORAGE_PATH, THUMB_DIR), { recursive: true });
|
||||
} catch (err: unknown) {
|
||||
if ((err as NodeJS.ErrnoException).code === "EACCES") {
|
||||
throw Object.assign(new Error("Storage directory is not writable"), { statusCode: 503 });
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
thumbDirReady = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,8 +61,15 @@ async function checkWorkspaceCapacity(workspaceRoot: string): Promise<void> {
|
||||
export async function createWorkspace(jobId: string): Promise<string> {
|
||||
await checkWorkspaceCapacity(env.WORKSPACE_PATH);
|
||||
const root = getWorkspacePath(jobId);
|
||||
await mkdir(join(root, "input"), { recursive: true });
|
||||
await mkdir(join(root, "output"), { recursive: true });
|
||||
try {
|
||||
await mkdir(join(root, "input"), { recursive: true });
|
||||
await mkdir(join(root, "output"), { recursive: true });
|
||||
} catch (err: unknown) {
|
||||
if ((err as NodeJS.ErrnoException).code === "EACCES") {
|
||||
throw Object.assign(new Error("Workspace directory is not writable"), { statusCode: 503 });
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user