Skip to content

[BUG]: Replicas downscale does not drain the requests #13559

Description

@RealNicolasBourbaki

Describe the Bug

Currently when a replica is shed, all in-flight and queued requests are aborted a fixed 5 s after SIGTERM (5 s = default DYN_GRACEFUL_SHUTDOWN_GRACE_PERIOD_SECS). Clients get HTTP 500 "Failed to fold completions stream". There is no stage that waits for inflight requests to reach zero.

Steps to Reproduce

  1. deploy the attached DGD
    dgd-drain-repro.yaml

  2. you can use your own load or use mine in the attachment to generate a trace: python3 make-trace.py --out trace.jsonl. This trace has 2 phases, phase 1 with TPS = 8.0 req/s, phase 2 with 0.2 req/s --> perfect to watch dynamo sheds replicas

  3. replay the trace against the deployment:
    FE=$(kubectl -n dynamo-system get svc drain-repro-frontend -o jsonpath='{.spec.clusterIP}') aiperf profile --model openai/gpt-oss-120b --tokenizer openai/gpt-oss-120b \ --endpoint-type completions --streaming --url http://$FE:8000 \ --input-file trace.jsonl --custom-dataset-type mooncake_trace \ --fixed-schedule --fixed-schedule-auto-offset \ --extra-inputs "ignore_eos:true" --artifact-dir ./aiperf-out

  4. observe the responses of the clients during replica shedding.make-trace.py

Expected Behavior

a de-registered worker finishes its in-flight requests before exiting, bounded by a timeout

Actual Behavior

The worker de-registers from discovery correctly, so no new requests are routed to it. It then sleeps a fixed 5 s and aborts everything that are still generating. Clients receive HTTP 500.

Worker log of the shed replica (Dynamo 1.4.0, gpt-oss-120b):

16:41:50.979  Unregistering endpoint: namespace=dynamo-system-drain-repro ...
16:41:51.004  Successfully unregistered endpoint instance - worker removed from routing
16:41:51.005  Grace period 5.00s before stopping endpoints
16:41:56.009  Initiating runtime shutdown                     # exactly 5.004 s later

On the client side, at that same instant, 18 of 1500 requests fail simultaneously:

{"message":"Failed to fold completions stream for cc14fa97-...","type":"Internal Server Error"}

graceful_shutdown_with_discovery aborts without draining. Here is what happens chronologically during downscale:

step source (v1.4.0)
unregister from discovery — correct graceful_shutdown.py#L104
await asyncio.sleep(grace_period_s), default 5.0 s #L108 / #L15
drain_callbackskipped, vLLM passes None #L110
shutdown_event.set() #L129-L130
every in-flight request calls engine_client.abort() handlers.py#L1827, #L1861
runtime.shutdown() #L149

Environment

  • Dynamo: 1.4.0 same as the planner and vllm-runtime versions
  • Inference engine: vllm-runtime 1.4.0 shipped by dynamo, based on vLLM 0.26.0
  • model: gpt-oss-120b
  • K8s: v1.34.8+k3s1
  • OS: Ubuntu 24.04.3 (kernel 6.8.0-71)
  • GPU: Nvidia h200

Additional Context

Just 2 FYIs:

  1. there is a request draining feature but for dynamo rust runtime shutdown (here). This never kicks in because SIGTERM first calls shutdown_event, aborts in-flight requests and stops background loops. Only after that the rust runtime starts to shutdown, and start draining. But at that time there is no requests to be drained anymore.

  2. (UPDATE: This is confirmed to be irrelevant after the discussion below) Dynamo already has a callbakc receiver: DynamoStatLoggerPublisher, whose record() receives a SchedulerStats every engine iteration (here), and that carries num_running_reqs and num_waiting_reqwhich might be useful for draining_callback

Screenshots

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    backend::vllmRelates to the vllm backendbugSomething isn't workingdeployment::k8sRelates to dynamo deployment in kubernetesdynamo-runtimeRelates to the dynamo-runtime componentfault tolerancefault-toleranceCODEOWNER area -> @ai-dynamo/dynamo-fault-tolerance-codeownerslanguage::pythonIssues/PRs that reference Python coderuntimeCODEOWNER area -> @ai-dynamo/dynamo-runtime-codeowners

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions