Graceful Shutdown & Request Draining
Overview​
When a pod in an llm-d deployment is terminated — during a scale-down, a rolling update, or a node drain — in-flight inference requests are at risk. Because inference requests are long-running and compute-intensive, abruptly killing a pod can fail requests that were seconds away from completing.
Handling termination gracefully spans two layers:
- Routing layer (Router / Endpoint Picker) — stop sending new requests to the terminating pod, and drain any requests still queued in the scheduler.
- Model server layer (vLLM) — let in-flight inference requests finish (or drain for a bounded window) before the process exits.
This guide covers graceful shutdown for general (non-disaggregated) serving. For prefill/decode disaggregation, where in-flight requests span multiple servers and KV caches are held across instances, see Disaggregated Serving Operations (vLLM).
The Kubernetes Pod Termination Sequence​
llm-d relies on the standard Kubernetes pod termination process:
- Termination triggered — the pod's state is set to
Terminating. InferencePoolupdate — the pod is removed from the endpoints of its associatedInferencePool, so the Router stops routing new traffic to it. (For standard Kubernetes objects this is equivalent to removal from aService.)preStophook — if defined, the container'spreStophook executes.SIGTERM— Kubernetes sendsSIGTERMto the main process in each container.- Termination grace period — the pod is given
terminationGracePeriodSeconds(default 30s) to exit. If it has not exited by the end of this window, Kubernetes sendsSIGKILLto force termination.
New traffic is handled automatically by step 2. The rest of this guide is about
what happens to requests that are already in flight when SIGTERM arrives.
Draining the Model Server (vLLM)​
How vLLM responds to SIGTERM determines whether in-flight requests are drained
or dropped:
- Default — vLLM immediately
abortsin-flight requests and exits. Those requests fail with an error status code. - With
--shutdown-timeout N— vLLM catchesSIGTERMand continues serving the currently running requests for up toNseconds. After the timeout, any requests still in flight areabortedand returned an error.
terminationGracePeriodSeconds must be greater than --shutdown-timeout
(plus a small buffer for the preStop hook and process cleanup). Otherwise
Kubernetes sends SIGKILL before the drain completes, and the graceful window
is never fully used.
Request Cancellation on Client Disconnect​
Independent of shutdown, model servers like vLLM support request
cancellation: when a client disconnects, the in-progress request is freed
rather than run to completion. When a request is disconnected, vLLM triggers its
abort codepath, releasing the KV cache and compute resources held by that
request.
This matters during shutdown and rolling updates: clients (or the gateway) that retry against a draining pod should disconnect the original request so its resources are reclaimed promptly instead of being held until the request finishes on its own.
For the disaggregated case — where a cancelled request may have KV blocks held on a separate prefill instance — see Request Cancellation.
Draining the Routing Layer (EPP)​
The Endpoint Picker (EPP) queues requests before dispatching them to model
servers. During a graceful shutdown, the EPP's flow controller evicts queued
requests with a retryable 503 Service Unavailable (outcome
rejected-shutting-down), signaling transient unavailability so that clients and
upstream gateways retry rather than treating the drain as a hard fault.
These retryable semantics only apply while the EPP is still reachable over its
ext_proc stream. Once the EPP process is actually gone, the outcome is governed
by the InferencePool's
failureMode. For high-availability
Router configurations and failOpen behavior during leader teardown, see
Router Operations.
For the full set of flow-control outcome codes, see Flow Control.
Recommended Configuration​
A model server pod configured for graceful draining:
apiVersion: v1
kind: Pod
metadata:
name: vllm
spec:
# Must exceed --shutdown-timeout plus a buffer for preStop + cleanup.
terminationGracePeriodSeconds: 120
containers:
- name: vllm
image: ghcr.io/llm-d/llm-d:latest
args:
- "--shutdown-timeout"
- "90" # Drain in-flight requests for up to 90s after SIGTERM.
ports:
- containerPort: 8000
protocol: TCP
# Readiness gates traffic; see readiness-probes.md.
readinessProbe:
httpGet:
path: /v1/models
port: 8000
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
Guidance:
- Set
--shutdown-timeoutto roughly the p99 request duration you want to allow to complete on drain. - Set
terminationGracePeriodSecondsabove that with headroom (here 120s vs 90s). - Pair with model-aware readiness probes so pods are only marked
Readyonce the model is loaded — see Readiness Probes.
Verification​
Send a long-running request, then delete the pod and confirm the request completes instead of failing:
# Start a long generation in the background against a target pod.
# Then trigger termination:
kubectl delete pod -n llm-d <pod-name>
# Watch the drain in the model server logs.
kubectl logs -n llm-d <pod-name> --tail=50 | grep -iE "shutdown|drain|abort|SIGTERM"
# Observe the pod staying in Terminating until the drain window elapses.
kubectl get pod -n llm-d <pod-name> -w
Expected behavior with --shutdown-timeout set:
- Pod enters
Terminating; it is removed from theInferencePool(no new traffic). - vLLM catches
SIGTERMand keeps serving in-flight requests. - The in-flight request completes successfully.
- The pod exits before
terminationGracePeriodSecondselapses (noSIGKILL).
Troubleshooting​
In-flight requests still fail on scale-down / rollout
- Confirm
--shutdown-timeoutis set; without it vLLM aborts immediately. - Confirm
terminationGracePeriodSeconds > --shutdown-timeout; otherwiseSIGKILLfires mid-drain.
Clients see hard errors instead of retries during shutdown
- Ensure clients/gateway treat
503as retryable — the EPP drains queued requests with a retryable503, not a fatal error. - Check the
InferencePoolfailureModefor behavior once the EPP is gone.