Skip to content

Commit aaac132

Browse files
committed
Fix for screenshots
1 parent f63dc7c commit aaac132

2 files changed

Lines changed: 25 additions & 3 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Cap concurrent renders. A profile grid requests many screenshots at once;
2+
// without this, N simultaneous compile+emulate+ffmpeg pipelines blow the
3+
// container's memory limit and it gets OOM-killed (clients see 502s). Queuing
4+
// keeps peak memory bounded — the cache makes the wait a one-time cost.
5+
const MAX = parseInt(process.env.MAX_CONCURRENT_RENDERS ?? '2', 10);
6+
7+
let active = 0;
8+
const waiters: Array<() => void> = [];
9+
10+
export async function withRenderSlot<T>(fn: () => Promise<T>): Promise<T> {
11+
if (active >= MAX) {
12+
await new Promise<void>((resolve) => waiters.push(resolve));
13+
}
14+
active++;
15+
try {
16+
return await fn();
17+
} finally {
18+
active--;
19+
waiters.shift()?.();
20+
}
21+
}

apps/gif-service/src/routes/screenshot.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { join } from 'path';
44
import { GIFGenerator } from '../gif-generator.js';
55
import { fetchProjectById } from '../hasura.js';
66
import { compileProjectIsolated } from '../compile-isolated.js';
7+
import { withRenderSlot } from '../concurrency.js';
78
import { CompileError } from '../errors.js';
89

910
const router = Router();
@@ -52,15 +53,15 @@ router.get('/:id', async (req: Request, res: Response) => {
5253
} else {
5354
let pending = inFlight.get(key);
5455
if (!pending) {
55-
pending = (async () => {
56+
pending = withRenderSlot(async () => {
5657
const tap = await compileProjectIsolated(project.lang, project.code);
57-
const generator = new GIFGenerator({ maxDurationMs: 4000, scale: 2 });
58+
const generator = new GIFGenerator({ maxDurationMs: 2500, scale: 2 });
5859
await generator.initialize();
5960
const out = await generator.generatePngFromTAP(tap, 48);
6061
await mkdir(CACHE_DIR, { recursive: true }).catch(() => undefined);
6162
await writeFile(file, out).catch(() => undefined);
6263
return out;
63-
})();
64+
});
6465
inFlight.set(key, pending);
6566
pending.finally(() => inFlight.delete(key));
6667
}

0 commit comments

Comments
 (0)