[Bugfix][KV Offloading] Defer request finalization until final store - #49671
Conversation
orozery
left a comment
There was a problem hiding this comment.
Thanks for the quick fix @Palaiologos1453 !
I actually made a fix, I think in some places it may be a bit cleaner.
Can you take a look and adapt things you think are better?
orozery@fa07027
I actually had to adapt some tests as well.
Enabling CI to verify.
nilig
left a comment
There was a problem hiding this comment.
Thanks for the quick fix. Verified it against the original #49635 deployment and reproducer: redeployed gpt-oss-120b with offload_prompt_only:false, block size 64, a P2P secondary tier, nightly-4080263b, the generic_p2p overlay at 145a460c, and this PR's scheduler.py.
The single ~2,900-token completion that previously killed EngineCore ~35-60 seconds after completion produced no restart for 100 seconds after each of two independent runs, nor through the rest of the session (further bursts, ~15 minutes). The 16-way same-prefix burst that previously returned 16x EngineDeadError completed 16/16, p50 0.27s. A 100-request burst completed 100/100. Cross-pod prefix pulls continue to work with the fix (seed 1.20s versus pull 0.19s, external prefix-cache hits covering ~the full prefix), and there were no tracebacks across the tested engines.
Non-blocking: wonder if we could also harden TieringOffloadingManager.prepare_store() against a future ordering regression. A missing _req_state entry should degrade to a skipped offload with a warning rather than an engine-wide EngineDeadError. The state check needs to happen after _maybe_process_finished_jobs() but before primary_tier.prepare_store(), since checking afterward could leave primary-tier allocation or bookkeeping without a corresponding completion. The retrieved state could then be reused for the pending_primary_stores and request_level_tiers accesses.
|
@orozery verified your variant (fa07027) the same way as the PR head: the #49635 cluster reproducers stay clean (0 restarts through the crash windows, 16/16 and 100/100 bursts, cross-pod pulls intact), and its test file passes 114/114 on our older |
|
Thanks @nilig ! |
Notify the offloading manager only after the scheduler has prepared a finished request's final store jobs. Preserve request state across same-step transfer completions and cover reset and async scheduling races. Signed-off-by: Rui Yin <2260891073@qq.com>
Centralize finished-request signaling after final store construction and make the scheduler test runner drain finished request steps and transfer completions. Co-authored-by: Or Ozeri <oro@il.ibm.com> Signed-off-by: Rui Yin <2260891073@qq.com>
cd06761 to
ecf6bc5
Compare
|
Thanks @orozery, I adapted the cleaner structure in The only part not copied from |
orozery
left a comment
There was a problem hiding this comment.
Thanks @Palaiologos1453 !
|
I investigated the remaining failures in Buildkite #79938:
The KV-offload-specific LM Eval jobs (1xH200, 2xH100, 4xH100) passed in #79938, and the reporter's production reproducer remains clean. Could the six unrelated/transient failures be retried? Our account does not have Buildkite retry permission. |
Port the lifecycle contract from upstream vLLM vllm-project#49671 so a tiering manager remains valid through deferred final-store preparation. Add synchronous and asynchronous regression coverage using the real TieringOffloadingManager, and make the scheduler test runner drain finished request steps. Co-authored-by: Or Ozeri <oro@il.ibm.com>
…ect#252) Port the lifecycle contract from upstream vLLM vllm-project#49671 so a tiering manager remains valid through deferred final-store preparation. Add synchronous and asynchronous regression coverage using the real TieringOffloadingManager, and make the scheduler test runner drain finished request steps. Co-authored-by: Or Ozeri <oro@il.ibm.com>
…ect#252) Port the lifecycle contract from upstream vLLM vllm-project#49671 so a tiering manager remains valid through deferred final-store preparation. Add synchronous and asynchronous regression coverage using the real TieringOffloadingManager, and make the scheduler test runner drain finished request steps. Co-authored-by: Or Ozeri <oro@il.ibm.com>
…ect#252) Port the lifecycle contract from upstream vLLM vllm-project#49671 so a tiering manager remains valid through deferred final-store preparation. Add synchronous and asynchronous regression coverage using the real TieringOffloadingManager, and make the scheduler test runner drain finished request steps. Co-authored-by: Or Ozeri <oro@il.ibm.com>
…ect#252) Port the lifecycle contract from upstream vLLM vllm-project#49671 so a tiering manager remains valid through deferred final-store preparation. Add synchronous and asynchronous regression coverage using the real TieringOffloadingManager, and make the scheduler test runner drain finished request steps. Co-authored-by: Or Ozeri <oro@il.ibm.com>
…ect#252) Port the lifecycle contract from upstream vLLM vllm-project#49671 so a tiering manager remains valid through deferred final-store preparation. Add synchronous and asynchronous regression coverage using the real TieringOffloadingManager, and make the scheduler test runner drain finished request steps. Co-authored-by: Or Ozeri <oro@il.ibm.com>
Purpose
Fixes #49635.
OffloadingConnectorScheduler.request_finished()currently notifies the manager before the scheduler prepares a finished request's deferred final store.TieringOffloadingManagercan then delete its request state, and the nextprepare_store()crashes EngineCore withKeyError.This change:
manager.on_request_finished();finished_req_idsand final transfer completions.The manager assertion remains strict so future lifecycle regressions are surfaced rather than silently dropping an offload.
Test Plan
prepare_store()precedeson_request_finished()whilecomplete_store()may follow it.Test Result
python -m ruff check vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py tests/v1/kv_connector/unit/offloading_connector/test_scheduler.py tests/v1/kv_connector/unit/offloading_connector/utils.py: passed.python -m ruff format --check ...: passed.python -m compileall -q ...: passed.