Skip to content

Idle unload

A model nobody uses gives the card back. After --model-idle-unload seconds (file key model.idle_unload, default 300) with no request in flight and nothing waiting or running on the engine, the server unloads the model the way a switch does — VRAM, pinned host memory and KV-RAM all freed — and stays up: the API, /metrics and the Playground keep answering, and GET /v1/models lists the same model with status: "unloaded". Meanwhile /metrics shows nothing reserved: the VRAM-plan, KV pool and KV-RAM gauges read zero until the next load. A switch sent during the seconds the unload tears the model down is refused 409 switch_in_progress naming the unload; send it again once GET /v1/models says unloaded.

The next request that needs the model — a chat completion, a response (over HTTP or on a WebSocket opened before the unload), a decision — loads it again and is answered once it is warm, so the first request after a quiet spell takes as long as a cold load (13–33 s on the 5090) and finds no retained prompt state. While it loads GET /v1/models says status: "loading", and requests arriving meanwhile wait for the same load rather than being refused. A request naming another model the server lists loads that model instead: one load, never two. A load that fails leaves status: "failed" with the reason, the requests that waited on it get 503 model_load_failed, and the next request tries again; POST /v1/models/switch (to the same id or another) and a PATCH /v1/config that needs a reload load a model too. A request without the API key is refused 401 as always and loads nothing.

Only use counts: a request is in use from its admission to the end of its response (a long stream keeps the model loaded); polling GET /v1/models, the config and catalog reads or /metrics does not, so a Playground left open neither keeps the model loaded nor loads it again. A transcription does not count either: the speech model is another model, on the CPU, with its own idle time (speech.idle_unload), and it is served with the text model unloaded without loading it. An unload and the load a request begins after it are logged (ignis.model.unloaded, ignis.model.reloaded) and are not a switch: last_switch is left as it was. A POST /v1/models/switch or a reloading PATCH /v1/config while unloaded is still a switch or a reload, and is recorded in last_switch like any other.

0 never unloads. The value is patchable live — PATCH /v1/config with {"model": {"idle_unload": 600}} takes effect at once, counting from the change. A measurement should not meet a cold reload: the Makefile’s IDLE_UNLOAD=0 passes --model-idle-unload 0, and the A/B and TTFT session scripts do so themselves.