Skip to content

fix: restrict memory from halting system - #474

Draft
ctrlaltf24 wants to merge 4 commits into
FaithLife-Community:mainfrom
ctrlaltf24:fix-enforce-maximum-memory
Draft

fix: restrict memory from halting system#474
ctrlaltf24 wants to merge 4 commits into
FaithLife-Community:mainfrom
ctrlaltf24:fix-enforce-maximum-memory

Conversation

@ctrlaltf24

Copy link
Copy Markdown
Contributor

Two-layer memory protection prevents a runaway Wine/Logos process (e.g.
the indexer) from exhausting the host.

Primary – systemd-run cgroup enforcement:
When systemd-run is available, wine commands are wrapped in a transient
user scope with MemoryMax set to 90% of currently-available RAM. The
kernel enforces the limit at the cgroup level with no polling overhead.
Availability is probed once at runtime and cached.

Fallback – Python RSS watchdog:
A background thread (LogosManager._memory_watchdog) polls the resident
set size of the entire Wine process tree every two seconds. The cap is
90% of the RAM that would be free if the monitored process were not
running (available + process_rss), so the process's own growing
footprint is never counted against its budget — only other processes
can move the ceiling. If the cap is exceeded, the process group is
SIGTERM'd with a 10-second grace period before escalating to SIGKILL.

The watchdog starts when Logos launches or indexing begins, and is
stopped cleanly by end_processes(). Also fixes the AppImage download
gate to skip the download when the wine binary is set to a recommended
or beta sigil.

Tested:

  • systemd-run cgroup path: Logos launched successfully inside a
    run-*.scope with MemoryMax=1612958515 (~90% of available RAM at
    launch). Scope appeared in systemctl --user list-units --type=scope.
  • Fallback path: after removing the systemd-run binary, no scope was
    created and Wine launched unwrapped; watchdog remains the sole enforcer.
  • Unit tests (13/13): all TestMemoryLimits and TestSystemdRunPrefix
    cases pass.
  • Polling watchdog kill path: NOT yet tested end-to-end (no spike test
    run against a live process).
  • Unittests on the polling watchdog as written

Have not tested with a real Logos installation - only mock tests. Mostly AI written tests. Would be wise to test manually if we know how to make the memory footprint trigger a crash

Fixes: #457

ctrlaltf24 and others added 3 commits June 15, 2026 16:54
Two-layer memory protection prevents a runaway Wine/Logos process (e.g.
the indexer) from exhausting the host.

Primary – systemd-run cgroup enforcement:
When systemd-run is available, wine commands are wrapped in a transient
user scope with MemoryMax set to 90% of currently-available RAM. The
kernel enforces the limit at the cgroup level with no polling overhead.
Availability is probed once at runtime and cached.

Fallback – Python RSS watchdog:
A background thread (LogosManager._memory_watchdog) polls the resident
set size of the entire Wine process tree every two seconds. The cap is
90% of the RAM that would be free if the monitored process were not
running (available + process_rss), so the process's own growing
footprint is never counted against its budget — only other processes
can move the ceiling. If the cap is exceeded, the process group is
SIGTERM'd with a 10-second grace period before escalating to SIGKILL.

The watchdog starts when Logos launches or indexing begins, and is
stopped cleanly by end_processes(). Also fixes the AppImage download
gate to skip the download when the wine binary is set to a recommended
or beta sigil.

Tested:
- systemd-run cgroup path: Logos launched successfully inside a
  run-*.scope with MemoryMax=1612958515 (~90% of available RAM at
  launch). Scope appeared in `systemctl --user list-units --type=scope`.
- Fallback path: after removing the systemd-run binary, no scope was
  created and Wine launched unwrapped; watchdog remains the sole enforcer.
- Unit tests (13/13): all TestMemoryLimits and TestSystemdRunPrefix
  cases pass.
- Polling watchdog kill path: NOT yet tested end-to-end (no spike test
  run against a live process).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves _memory_watchdog, _hard_kill, and related state out of LogosManager
into a standalone MemoryWatchdog class (ou_dedetai/watchdog.py) with no
App dependency — LogosManager wraps run() and calls app.exit() if
kill_reason is set after the loop returns.

Adds tests/test_watchdog.py covering: real-subprocess kill with a
dynamically-measured baseline RSS cap, dead-process/NoSuchProcess/non-Popen
skip paths, clean stop, reset, and SIGTERM→SIGKILL escalation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ctrlaltf24
ctrlaltf24 requested review from n8marti and thw26 June 16, 2026 08:01
@ctrlaltf24 ctrlaltf24 changed the title Fix enforce maximum memory fix: restrict memory from halting system Jun 16, 2026
@ctrlaltf24

This comment was marked as outdated.

Comment thread ou_dedetai/logos.py Outdated
@pydsigner

Copy link
Copy Markdown

Would be wise to test manually if we know how to make the memory footprint trigger a crash

I was able to trigger a full system OOM freeze by opening enough Logos tabs to nearly fill system memory and then opening another Electron app that presumably triggered an overcommit. I've also been able to cause the OOM killer to terminate other apps by opening enough Logos resources. Do either of those cases sound like what you're seeking live testing for on this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Limit Logos Memory Usage

2 participants