-
Stefy Lanza (nextime / spora ) authored
Measured on zeiss 2026-11-01: eviction freed 12.2 GB of the 18.0 GB needed and stopped 1.5 GB short -- "held by a busy model or another process" -- and Z-Image-Turbo loaded with CPU/disk offload. The room it needed was not unavailable. It was in use, by a request that was about to finish. Waiting for a model to go idle and then taking its VRAM was already the house rule for the active model and the keep-resident set. Ordinary LRU models were the exception: pass 1 printed "is busy serving a request — not evicting it" and moved on. Three deadlines elsewhere were the same exception in a different dress, because a deadline here does not avert a hang -- it converts "this load waits a few seconds" into "this load runs on the CPU for its whole life", with nothing in the log to say why. So every pass now waits: idle LRU evict (first: it costs nothing) busy LRU wait, then evict was "not evicting it" active model wait, then evict was 120s, else leave loaded keep-resident wait, then evict was 120s, else leave loaded _evict_one wait, then evict was 120s, else "Skipping eviction" and the give-up branches are deleted rather than left as dead code describing an exception that no longer exists. _wait_until_idle defaults to no deadline. The busy ones are a SECOND sweep rather than inline waits, so a cheap idle eviction further down the LRU order never queues behind a wait that may turn out to be unnecessary. Two things keep an unbounded wait from being a hang, and both already held: the pass never waits on `protect` -- the key the room is being made FOR, the one model that provably cannot go idle because it is blocked on the memory being freed -- and a model unloaded under us ends the wait. The wait also repeats itself every 15 s, so a genuinely hung generation is legible AS a hung generation instead of as an eviction that stopped responding. Two waits stay bounded, deliberately, and are now asserted as such so neither drifts back by accident: * unload_model, an operator action with a caller waiting on an answer, where "not unloaded" is a perfectly good answer. Eviction has no such option. * the host-RAM evictor, untouched. Waiting there risks the kernel's OOM killer taking the whole engine -- four times in five hours the night that code was written. Different resource, different failure mode, separate decision. test_the_source_never_waits_on_the_protected_model read src[i:i+6000] and failed because this function grew past it, while the guarantee it protects was intact; it is now bounded by the next method, like the other source tests here. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014T3rZozi1Ehk96NG1WesgC
6176ff05