-
Stefy Lanza (nextime / spora ) authored
Builds on the cross-engine clean-swap eviction: instead of two engines on one shared card ever running forwards concurrently (→ VRAM contention → OOM → disk-thrash), the front now serializes model OWNERSHIP of a shared GPU while batching to avoid per-request thrash. New GpuSwapGate (frontproxy/reqqueue.py), one per shared-GPU group (keyed by the co-located engines' CODERAI_ENGINE_GPUS selector, created only when an engine has a sibling on its card): * A request for the model that currently OWNS the GPU runs immediately — a swap isn't needed (a lone stream never stalls). Concurrency stays capped downstream by the existing per-model FrontQueue. * A request for a DIFFERENT model queues. The owner keeps being served up to `cap` requests (server.gpu_swap_batch, default 10) while another model waits, then — once the owner is fully idle (never mid-request) — the GPU SWAPS to the waiting model (which evicts + loads), serves it, and round-robins BACK if the original has requests queued. No thrash (batch), no starvation (cap). Wired into all four dispatch paths (broker, broker-stream, direct stream with keepalive, direct non-stream) for every GPU-inference kind (text/image/video): acquire the swap slot before the per-model queue, release in the finalizer; cancelling a pending acquire (client disconnect) drops the waiter with no leak. The text-stream path emits keepalives while waiting out a swap so the client doesn't time out. Scheduler validated by async unit tests: cap engages at exactly N with a competitor waiting; a lone same-model stream runs unbounded; round-robin alternates; cancelled waiters leak no slot. Co-Authored-By:Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
c0a970b0