fix(service): bound ejclaw cgroup page cache with MemoryHigh=3G
Per-turn agent runners do heavy file I/O (git clone, builds, ffmpeg/video scratch) inside the ejclaw service cgroup. The kernel retains those reads as reclaimable page cache, so systemd's MemoryCurrent climbs to 4-5GB even though real anon usage stays ~300MB and the host has 13GB free. Add a soft MemoryHigh so the cache is reclaimed under pressure before the number balloons; MemoryMax stays unset (infinity) so a legitimate burst is throttled, never OOM-killed. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,15 @@ WorkingDirectory=${projectRoot}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
RestartPreventExitStatus=${STARTUP_PRECONDITION_EXIT_CODE}
|
||||
# Per-turn agent runners do heavy file I/O (git clone, builds, video/ffmpeg
|
||||
# scratch) inside this service cgroup. The kernel keeps those reads as
|
||||
# reclaimable page cache, which makes systemd's MemoryCurrent climb to several
|
||||
# GB even though real (anon) usage stays a few hundred MB. MemoryHigh applies
|
||||
# gentle reclaim pressure so that cache is dropped before the number balloons,
|
||||
# while MemoryMax stays unset (infinity) so a legitimate burst is never
|
||||
# OOM-killed — it is throttled at worst.
|
||||
MemoryAccounting=yes
|
||||
MemoryHigh=3G
|
||||
${envLines.join('\n')}
|
||||
StandardOutput=append:${projectRoot}/logs/${def.logName}.log
|
||||
StandardError=append:${projectRoot}/logs/${def.logName}.error.log
|
||||
|
||||
@@ -111,6 +111,20 @@ describe('systemd unit generation', () => {
|
||||
expect(unit).toContain('RestartPreventExitStatus=78');
|
||||
});
|
||||
|
||||
it('bounds reclaimable page cache with a soft memory limit', () => {
|
||||
const unit = buildSystemdUnit(
|
||||
baseServiceDef,
|
||||
'/home/user/ejclaw',
|
||||
'/usr/bin/node',
|
||||
'/home/user',
|
||||
false,
|
||||
);
|
||||
expect(unit).toContain('MemoryAccounting=yes');
|
||||
expect(unit).toContain('MemoryHigh=3G');
|
||||
// MemoryMax must stay unset so a real burst is throttled, never OOM-killed.
|
||||
expect(unit).not.toContain('MemoryMax=');
|
||||
});
|
||||
|
||||
it('sets correct ExecStart', () => {
|
||||
const unit = buildSystemdUnit(
|
||||
baseServiceDef,
|
||||
|
||||
Reference in New Issue
Block a user