Home / Docs / GPU sandboxes / Pause semantics

GPU pause semantics — leases that run graphics/child processes

What pause does depends on the lease's suspend_mode. The rules on this page come from measurements on an A10 GPU host (2026-10-09) with graphics, simulation and game-engine workloads.

What those measurements showed:

Semantics

suspend_modepauseresumeseatVRAM
transparent, no non-worker VRAM, or a host without a hard capfreeze every non-worker lease process (SIGSTOP on the worker's cgroup members / process group), then release + cuda-checkpoint (the plain transparent path)cuda-checkpoint back, capped reserve, then SIGCONT childrenfreed (worker's slice spills; on a hard-cap host the reading shows no child VRAM)worker spilled
transparent on a hard-cap host, non-worker VRAM > 0 or probe unavailablefreeze the whole lease (docker pause; SIGSTOP process group for a host worker) — no toggle, no release/reservedocker unpause / SIGCONTheldfully resident
nonefreeze the whole container (docker pause; SIGSTOP process group for a host worker)docker unpause / SIGCONTheldfully resident

Billing — frozen-resident is billed in full

A frozen lease — a none pause, or a freeze-only transparent suspend — keeps accruing billed_s == resident_s through the freeze. Justification: the lease still exclusively holds its VRAM slice and its seat — resident GPU memory is not free capacity, and freezing changes nothing the operator could sell to someone else. A free pause would be a billing-dodge vector (hold the card, stop the meter). A freeze-only transparent suspend bills only its actual frozen intervals in full (frozen_billed_s); the freeze_only flag clears on thaw, so the rest of the residency bills like a transparent lease (busy + idle + resume) — one freeze-only interval must not reclassify the lease's whole lifetime residency as billed. New observability meters: frozen_s, freezes. Settled freeze-only intervals are emitted as a billed busy usage row (the same treatment a none pause's residency gets in memory): the store charges only busy/resume rows, so a frozen interval that emitted nothing — or an analytics running row — would be billed in memory but free after a restart. On the front+node topology the front settles the node's frozen_billed_s counter into its own gpu_usage as that same charged busy component (one frontier per kind shared with the exec's busy seconds, so the interval lands exactly once: a reply re-read adds 0 and a front restart re-seeds from the durable trail instead of billing it twice). A none lease is the exception there: the front charges its residency (running_s) as that busy component, in place of the exec and idle seconds inside it, which is what the node bills.

A freeze-only interval open on a lease that restores dead — adoption fails, the row cannot continue the freeze — settles at the previous process's last sign of life as a billed busy row and closes. Left open it would accrue on a dead row forever and a later destroy would flush the whole outage as one inflated busy row (a purge drops it instead).

A spilled transparent lease bills 0 while it is paused, as before. On a hard-cap host a pause spills only when the usage probe can read the lease's VRAM and no non-worker VRAM is resident; a host without a hard cap has no probe and always spills. On a hard-cap host a transparent suspend with resident non-worker VRAM (or an unreadable probe) does not spill at all, whether or not the worker has child processes: it is freeze-only, holds its seat, and bills its frozen time in full.

The figures above are the lease's meters, and they hold on every deployment. The credit bucket is drawn for them on a single GPU host and on a node fleet alike: on a node fleet the front settles busy and resume seconds (a freeze-only transparent lease's frozen interval counts as busy, and so does a none lease's whole residency, its frozen time included), and on a single GPU host the ledger charges the same. See Billing.

Watchdog + resume accounting (hard-cap)

Failure modes

failureoutcome
docker pause / SIGSTOP failsfrozen intent rolls back, pause errors 409, lease stays resident
child SIGSTOP fails mid-suspendalready-stopped pids SIGCONTed, suspend refused, phase resident
suspend toggle fails after children frozeclaim rolls back, children thawed
resume toggle failslease stays suspended, children stay frozen
thaw (docker unpause / SIGCONT) fails on resume/exec of a frozen leaseresume/exec errors; the commit lands only after the thaw succeeds, so the lease stays frozen (container still paused, seat held, residency still billing)
pause/resume/exec while another thaw is in flightwaits for that thaw to commit (one thaw claims the lease), then re-checks under the lock: a second exec or a pause of a lease the thaw's job now holds is refused; a resume whose lease was destroyed mid-thaw raises
gateway restart, freeze-only interval, lease not re-adoptedthe interval settles at the last sign of life as a billed busy row and closes; the dead row stops accruing and its destroy/purge flush stays at the interval
gateway restartadopted resident lease with recorded real frozen_pids thaws them (a transparent freeze's children); an adopted whole-container freeze (no child pids recorded) stays paused — unpause runs only from a thaw that also commits frozen=false; adopted suspended keeps its children frozen; frozen flag persists (docker pause survives)
dead worker / destroy while frozenkill paths reap stopped processes; the open freeze-only interval settles as a billed busy row; nothing special

Idle auto-pause (accel.idle_timeout_s)

A lease that sits idle holds a seat on the card. Create takes an optional accel.idle_timeout_s: 0 disables auto-pause, otherwise a number of seconds in [60, 86400]; anything else is a 400 naming the field. A free-tier key keeps auto-pause on: 0 or more than 600 s is a 403 gpu_free_tier_limit (param accel.idle_timeout_s). Omitted:

suspend_modedefaultwhy
transparent600 s (GATEWAY_GPU_IDLE_AUTOPAUSE_S)pause spills VRAM and frees the seat, unless the pause freezes the lease (non-worker VRAM on a hard-cap host, see Semantics): a frozen lease keeps its seat and its frozen time bills in full. A spilled idle transparent lease bills 0, so parking it is free for the tenant. 600 s equals the plane's existing max_idle_hold_s, so the default changes nothing observable.
nonedisabled (0)its pause is freeze-only: the seat stays held and the residency still bills, so auto-pausing frees nothing. A tenant can still opt in with an explicit value (a freeze)

The sweep runs in reap_idle (same timer as the existing reaper) and calls pause() — the POST /pause path — for a resident, non-frozen lease with no job in flight whose last activity (create, exec end, resume or thaw) is older than its timeout. Locks, freeze-only rules and billing are the manual verb's; a sweep that races an exec is refused like a manual pause and retried next tick. Exec or resume on the paused lease thaws it exactly as after a manual pause. A longer value does not stop the plane's existing seat-demand, memory-pressure and max_idle_hold_s parking of transparent leases.

GET /sandboxes/{id} meters carry idle_timeout_s and auto_paused (pauses the sweep fired). Kill switch: GATEWAY_GPU_IDLE_AUTOPAUSE=0 (flag on by default; the sweep only parks leases the plane was already parking at 600 s unless the tenant names a timeout).

Next: GPU sandboxes · errors