Skip to content

feat(server): evict cached model sessions to keep RAM bounded#6

Merged
tecnomanu merged 1 commit into
mainfrom
feat/model-eviction
Jun 22, 2026
Merged

feat(server): evict cached model sessions to keep RAM bounded#6
tecnomanu merged 1 commit into
mainfrom
feat/model-eviction

Conversation

@tecnomanu

Copy link
Copy Markdown
Owner

Summary

The Electron app could grow past 20 GB because every model the user touched stayed loaded in _SESSIONS forever. This PR caps that:

  • Idle TTL evictor: a background sweeper unloads sessions that have been idle for RBL_MODEL_IDLE_TTL seconds (default 600). The pinned model is exempt — it's the one the user is actively working with.
  • POST /set_default_model: the UI calls this when the global model dropdown changes. The previous model is immediately dropped from RAM so we don't pile up BiRefNet + ISNet + U2Net at once.
  • POST /remove?transient=true: per-image reprocess with a different model loads it but does not steal the pinned default. The idle TTL reclaims it later.
  • POST /unload_model: manual free without touching the on-disk .onnx cache.
  • GET /health: now reports pinned_model and idle_ttl_seconds.

UI wired:

  • Picking a model in the dropdown → pinDefaultModel(model) → evicts everything else.
  • reprocessJob(job, newModel) flags the request as transient when the model differs from the global one.

Test plan

  • ./run_tests.sh — 26 tests pass (10 new covering _evict, sweep, /unload_model, /set_default_model, transient remove, health payload).
  • E2E against a real server.py with RBL_MODEL_IDLE_TTL=4:
    • /set_default_model rotates pin and evicts the previous one ✅
    • Idle TTL sweeps non-pinned sessions but spares the pinned one ✅
    • /remove with transient=true returns a valid PNG and does not change the pinned model ✅
  • Manual sanity in the Electron app (the user can confirm RAM stays bounded after switching models a few times).

🤖 Generated with Claude Code

The Electron app was growing past 20 GB because every model the user
touched stayed loaded in `_SESSIONS` forever. Three knobs to fix that:

- Idle TTL: a background sweeper unloads sessions that have not been
  used in `RBL_MODEL_IDLE_TTL` seconds (default 600). The pinned model
  is exempt — it is the one the user is actively working with.
- /set_default_model: when the UI changes the global model dropdown,
  the previous one is evicted from RAM immediately so we don't pile
  up BiRefNet + ISNet + U2Net at once.
- /remove?transient=true: per-image overrides (reprocess) load their
  model but do not steal the pinned default. The idle TTL reclaims
  them later.

Plus /unload_model for manual freeing without touching the on-disk
cache, and /health now reports the pinned model + TTL.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tecnomanu
tecnomanu merged commit 7751ffe into main Jun 22, 2026
2 checks passed
@tecnomanu
tecnomanu deleted the feat/model-eviction branch June 22, 2026 13:20
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.

1 participant