mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: upscale tool times out on CPU-only systems (NAS/low-power hardware)
The upscale function called runPythonWithProgress without a timeout parameter, defaulting to the bridge's 10-minute hard limit. On CPU-only systems like Synology NAS devices, Real-ESRGAN 4x upscaling easily exceeds this for modest images. Additionally, when the timeout fired on the dispatcher path, the Python process was left running and blocked all subsequent AI operations. This fix adds an adaptive timeout based on input megapixels, scale factor, and GPU availability (180s/effective-MP on CPU, 30s/effective-MP on GPU, floor of 10 minutes). It also kills the dispatcher on timeout so subsequent requests can proceed via a fresh restart. Closes #119
This commit is contained in:
@@ -266,6 +266,11 @@ function dispatcherRun(
|
||||
return new Promise((resolvePromise, rejectPromise) => {
|
||||
const timer = setTimeout(() => {
|
||||
pendingRequests.delete(id);
|
||||
// Kill the stuck dispatcher so it restarts on the next request instead of
|
||||
// blocking all subsequent AI operations behind the timed-out script.
|
||||
if (dispatcher && !dispatcher.killed) {
|
||||
dispatcher.kill("SIGTERM");
|
||||
}
|
||||
rejectPromise(new Error("Python script timed out"));
|
||||
}, timeout);
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import sharp from "sharp";
|
||||
import { type ProgressCallback, parseStdoutJson, runPythonWithProgress } from "./bridge.js";
|
||||
import {
|
||||
isGpuAvailable,
|
||||
type ProgressCallback,
|
||||
parseStdoutJson,
|
||||
runPythonWithProgress,
|
||||
} from "./bridge.js";
|
||||
|
||||
export interface UpscaleOptions {
|
||||
scale?: number;
|
||||
@@ -31,10 +36,19 @@ export async function upscale(
|
||||
|
||||
const pngBuffer = await sharp(inputBuffer).png().toBuffer();
|
||||
await writeFile(inputPath, pngBuffer);
|
||||
|
||||
const meta = await sharp(pngBuffer).metadata();
|
||||
const megapixels = ((meta.width ?? 0) * (meta.height ?? 0)) / 1_000_000;
|
||||
const scale = options.scale ?? 2;
|
||||
const effectiveMp = megapixels * scale ** 2;
|
||||
// CPU inference is ~50-100x slower than GPU; be generous for self-hosted NAS hardware
|
||||
const rateMs = isGpuAvailable() ? 30_000 : 180_000;
|
||||
const timeout = Math.max(600_000, effectiveMp * rateMs);
|
||||
|
||||
const { stdout } = await runPythonWithProgress(
|
||||
"upscale.py",
|
||||
[inputPath, outputPath, JSON.stringify(options)],
|
||||
{ onProgress },
|
||||
{ onProgress, timeout },
|
||||
);
|
||||
|
||||
const result = parseStdoutJson(stdout);
|
||||
|
||||
Reference in New Issue
Block a user