mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
fix(og): aggressive GC to prevent OOM in constrained containers
Full OG regeneration (2,350 images) was OOM-killed because WASM native memory from Satori/Resvg accumulated between GC cycles. The previous GC interval of 50 images allowed ~2.5-5 GB of native allocations before reclamation. Reduce to every 5 images to keep peak RSS under ~400 MB. Also reduce --max-old-space-size from 768 to 512 MB (V8 heap only uses ~22 MB) and add peak RSS tracking to the completion log. Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
This commit is contained in:
@@ -1123,7 +1123,7 @@ export default function (eleventyConfig) {
|
||||
const siteName = process.env.SITE_NAME || "My IndieWeb Blog";
|
||||
try {
|
||||
execFileSync(process.execPath, [
|
||||
"--max-old-space-size=768",
|
||||
"--max-old-space-size=512",
|
||||
"--expose-gc",
|
||||
resolve(__dirname, "lib", "og-cli.js"),
|
||||
contentDir,
|
||||
|
||||
18
lib/og.js
18
lib/og.js
@@ -298,8 +298,13 @@ export async function generateOgImages(contentDir, cacheDir, siteName) {
|
||||
let skipped = 0;
|
||||
const newManifest = {};
|
||||
const SAVE_INTERVAL = 10;
|
||||
const GC_INTERVAL = 50;
|
||||
// GC every 5 images to keep WASM native memory bounded.
|
||||
// Satori (Yoga WASM) + Resvg (Rust WASM) allocate ~50-100 MB native memory
|
||||
// per image that V8 doesn't track. Without aggressive GC, native memory
|
||||
// grows unbounded and OOM-kills the process in constrained containers.
|
||||
const GC_INTERVAL = 5;
|
||||
const hasGC = typeof global.gc === "function";
|
||||
let peakRss = 0;
|
||||
|
||||
for (const filePath of mdFiles) {
|
||||
const raw = readFileSync(filePath, "utf8");
|
||||
@@ -333,25 +338,28 @@ export async function generateOgImages(contentDir, cacheDir, siteName) {
|
||||
newManifest[slug] = { title: slug, hash };
|
||||
generated++;
|
||||
|
||||
// Save manifest periodically to preserve progress
|
||||
// Save manifest periodically to preserve progress on OOM kill
|
||||
if (generated % SAVE_INTERVAL === 0) {
|
||||
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));
|
||||
}
|
||||
|
||||
// Force GC to reclaim Satori/Resvg WASM native memory.
|
||||
// V8 doesn't track native heap (Satori Yoga WASM + Resvg Rust WASM),
|
||||
// so without periodic GC the JS wrappers accumulate and native memory
|
||||
// grows unbounded. With --expose-gc this keeps peak RSS under control.
|
||||
// so without frequent GC the JS wrappers accumulate and native memory
|
||||
// grows unbounded. Every 5 images keeps peak RSS under ~400 MB.
|
||||
if (hasGC && generated % GC_INTERVAL === 0) {
|
||||
global.gc();
|
||||
const rss = process.memoryUsage().rss;
|
||||
if (rss > peakRss) peakRss = rss;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasGC) global.gc();
|
||||
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));
|
||||
const mem = process.memoryUsage();
|
||||
if (mem.rss > peakRss) peakRss = mem.rss;
|
||||
console.log(
|
||||
`[og] Generated ${generated} images, skipped ${skipped} (cached or have photos)` +
|
||||
` | RSS: ${(mem.rss / 1024 / 1024).toFixed(0)} MB, heap: ${(mem.heapUsed / 1024 / 1024).toFixed(0)} MB`,
|
||||
` | RSS: ${(mem.rss / 1024 / 1024).toFixed(0)} MB, peak: ${(peakRss / 1024 / 1024).toFixed(0)} MB, heap: ${(mem.heapUsed / 1024 / 1024).toFixed(0)} MB`,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user