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";
|
const siteName = process.env.SITE_NAME || "My IndieWeb Blog";
|
||||||
try {
|
try {
|
||||||
execFileSync(process.execPath, [
|
execFileSync(process.execPath, [
|
||||||
"--max-old-space-size=768",
|
"--max-old-space-size=512",
|
||||||
"--expose-gc",
|
"--expose-gc",
|
||||||
resolve(__dirname, "lib", "og-cli.js"),
|
resolve(__dirname, "lib", "og-cli.js"),
|
||||||
contentDir,
|
contentDir,
|
||||||
|
|||||||
18
lib/og.js
18
lib/og.js
@@ -298,8 +298,13 @@ export async function generateOgImages(contentDir, cacheDir, siteName) {
|
|||||||
let skipped = 0;
|
let skipped = 0;
|
||||||
const newManifest = {};
|
const newManifest = {};
|
||||||
const SAVE_INTERVAL = 10;
|
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";
|
const hasGC = typeof global.gc === "function";
|
||||||
|
let peakRss = 0;
|
||||||
|
|
||||||
for (const filePath of mdFiles) {
|
for (const filePath of mdFiles) {
|
||||||
const raw = readFileSync(filePath, "utf8");
|
const raw = readFileSync(filePath, "utf8");
|
||||||
@@ -333,25 +338,28 @@ export async function generateOgImages(contentDir, cacheDir, siteName) {
|
|||||||
newManifest[slug] = { title: slug, hash };
|
newManifest[slug] = { title: slug, hash };
|
||||||
generated++;
|
generated++;
|
||||||
|
|
||||||
// Save manifest periodically to preserve progress
|
// Save manifest periodically to preserve progress on OOM kill
|
||||||
if (generated % SAVE_INTERVAL === 0) {
|
if (generated % SAVE_INTERVAL === 0) {
|
||||||
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));
|
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force GC to reclaim Satori/Resvg WASM native memory.
|
// Force GC to reclaim Satori/Resvg WASM native memory.
|
||||||
// V8 doesn't track native heap (Satori Yoga WASM + Resvg Rust WASM),
|
// V8 doesn't track native heap (Satori Yoga WASM + Resvg Rust WASM),
|
||||||
// so without periodic GC the JS wrappers accumulate and native memory
|
// so without frequent GC the JS wrappers accumulate and native memory
|
||||||
// grows unbounded. With --expose-gc this keeps peak RSS under control.
|
// grows unbounded. Every 5 images keeps peak RSS under ~400 MB.
|
||||||
if (hasGC && generated % GC_INTERVAL === 0) {
|
if (hasGC && generated % GC_INTERVAL === 0) {
|
||||||
global.gc();
|
global.gc();
|
||||||
|
const rss = process.memoryUsage().rss;
|
||||||
|
if (rss > peakRss) peakRss = rss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasGC) global.gc();
|
if (hasGC) global.gc();
|
||||||
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));
|
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));
|
||||||
const mem = process.memoryUsage();
|
const mem = process.memoryUsage();
|
||||||
|
if (mem.rss > peakRss) peakRss = mem.rss;
|
||||||
console.log(
|
console.log(
|
||||||
`[og] Generated ${generated} images, skipped ${skipped} (cached or have photos)` +
|
`[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