mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(throttle): use /proc/meminfo MemAvailable on Linux (#556)
`getMemoryUsage()` in src/core/backoff.ts computes 1 - freemem()/totalmem(), where Node's `os.freemem()` returns Linux's `MemFree`. `MemFree` excludes the page cache, which the kernel grows aggressively in any environment that reads files (i.e. essentially all containers). On a healthy 4 GB Linux container with ~1.4 GB MemAvailable, MemFree is routinely ~100 MB, so `getMemoryUsage()` reports 96-97% used and `waitForCapacity()` rejects every job with: Throttle timeout: system overloaded after 20 attempts (~600s). Load: ..%, Memory: 97% even though the host has plenty of usable memory. Linux exposes `MemAvailable` in `/proc/meminfo` precisely as the kernel's estimate of memory available for new allocations without swapping (it factors in reclaimable page cache). This is what `htop` and `free -h` show as "available". Using it removes the false positive entirely. Behaviour: - On Linux (when /proc/meminfo is readable): use 1 - MemAvailable/MemTotal. - Anywhere else (macOS, Windows, sandboxed envs without /proc): unchanged fallback to 1 - freemem()/totalmem(). Scope is intentionally minimal — data correctness only. An env override like GBRAIN_MEMORY_STOP_PCT would also be reasonable but is out of scope here. Co-authored-by: Kevin Hsu <kevinhsu.ecofirst@gmail.com>
This commit is contained in:
@@ -81,6 +81,20 @@ function getLoad(): number {
|
||||
|
||||
/** Get memory usage fraction (0-1) */
|
||||
function getMemoryUsage(): number {
|
||||
// Prefer /proc/meminfo MemAvailable on Linux — os.freemem() returns
|
||||
// MemFree which excludes page cache, falsely reading "high pressure"
|
||||
// in any container where the kernel caches files.
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs');
|
||||
const meminfo: string = fs.readFileSync('/proc/meminfo', 'utf8');
|
||||
const totalKb = Number(meminfo.match(/MemTotal:\s+(\d+)/)?.[1]);
|
||||
const availKb = Number(meminfo.match(/MemAvailable:\s+(\d+)/)?.[1]);
|
||||
if (totalKb > 0 && availKb >= 0) return 1 - availKb / totalKb;
|
||||
} catch {
|
||||
/* fall through to os.freemem() (non-Linux or /proc unavailable) */
|
||||
}
|
||||
// Non-Linux fallback (macOS, Windows, or any host without /proc/meminfo)
|
||||
const total = totalmem();
|
||||
if (total === 0) return 0;
|
||||
return 1 - (freemem() / total);
|
||||
|
||||
Reference in New Issue
Block a user