Skip to content

fix(ai): fail vLLM prompt queries on request errors instead of hanging - #7643

Open
TanishGudise wants to merge 2 commits into
Eventual-Inc:mainfrom
TanishGudise:fix/vllm-executor-surface-errors
Open

TanishGudise wants to merge 2 commits into
Eventual-Inc:mainfrom
TanishGudise:fix/vllm-executor-surface-errors

Conversation

@TanishGudise

Copy link
Copy Markdown

Changes Made

If one request fails, prompt(..., provider="vllm-prefix-caching") never finishes. Locally the error is never shown; on Ray it only shows up in the actor log as "Task exception was never retrieved".

Repro (CPU only, fake engine, in the new tests/ai/vllm/test_vllm_executor.py): three prompts, and AsyncLLMEngine.generate() raises for one of them. On main, df.collect() never returns: VLLMSink::finalize polls all_tasks_finished() every 500 ms and it stays False.

Cause: LocalVLLMExecutor._generate decrements running_task_count only after a successful generate, and nothing reads the exception, because the run_coroutine_threadsafe futures (and, in Ray actors, the create_task tasks) are dropped.

Fix:

  • _generate decrements the count in a finally and keeps the first exception, including cancellation; poll() and all_tasks_finished() re-raise it. The query now fails with the engine's own exception (on Ray with single-partition input, wrapped in RayTaskError). The re-raise matters: with only the finally, the query finishes with 2 of 3 rows and no error.
  • _periodic_log() was created after loop.run_forever(), which only returns once the loop stops, so it never ran. It now starts on the first submit(), on the same loop as the requests. It updates last_log_time so the per-request fallback rarely logs twice, and it stops once a request has failed, or once submitting is finished and no requests are running. Ray actors use submit_async and keep the per-request fallback, as before.

Tests: 6 new tests with a fake vllm module, no GPU needed. On main, 5 of them fail (the end-to-end one hits its 30 s timeout); with this change all 6 pass. I also ran the full native suite locally on this exact code: 60,433 passed, and every failure but one also fails on main in the same environment (mostly tests that need network access, model downloads, S3/minio or generated TPC-H data). The exception, tests/test_subscribers.py::test_capture_states (a SIGINT timing test), passes 3 of 3 times when rerun alone, on this branch and on main.

Not changed here: on Ray, a query whose input has more than one partition can return fewer rows than it got or hang, with or without a failing request (e.g. 4 of 40 rows after .repartition(4) with a fake engine and no failures), and then the error from this change may not surface either. That looks like a separate problem in how PrefixRouter tracks executors; I can file it separately.

AI disclosure: I used Claude while writing this fix and its tests; I reviewed every line, ran the full suite locally, and can answer questions about any of it.

Related Issues

Closes #7642

LocalVLLMExecutor._generate only decremented running_task_count after a
successful generate, and the futures holding the exception were dropped,
so one failing request left VLLMSink::finalize polling forever.

Decrement in a finally, keep the first exception (including
cancellation), and re-raise it from poll() and all_tasks_finished().

_periodic_log was created after loop.run_forever() returned, so it never
ran. Start it on the first threaded submit(), and stop it once a request
fails or all requests are done.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@TanishGudise
TanishGudise requested a review from a team as a code owner October 26, 2026 03:49
@github-actions github-actions Bot added the fix label Oct 26, 2026
@greptile-apps

greptile-apps Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes affect the vLLM prompt workflow in local runs and Ray actors.

The PR appears safe to merge, with a non-blocking cleanup issue in the test fixture.

Findings

  1. P2 Tests leave unfinished tasks ▶

Summary

The PR makes failed vLLM requests fail the query instead of leaving it waiting forever.

  • Failed vLLM requests now surface as query errors.
  • Local vLLM stats logging starts with the first request.

The only finding is non-blocking test cleanup: the fixture should cancel pending tasks and close its loop.

Acknowledged scope: TanishGudise explicitly defers the existing Ray routing problem with multiple input partitions as a separate issue. TanishGudise also states that Ray keeps the existing per-request logging fallback.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Submit prompts] --> B[Run each request]
  B --> C{Request succeeds?}
  C -->|Yes| D[Queue output]
  C -->|No| E[Save first error]
  D --> F[Lower running count]
  E --> F
  F --> G[Poll or check completion]
  G --> H{Saved error?}
  H -->|Yes| I[Fail query]
  H -->|No| J[Return outputs or keep waiting]
Loading

Reviews (1) · Last reviewed commit: "fix(ai): fail vLLM prompt queries on req..." · Reviewed by Greptile

Comment thread tests/ai/vllm/test_vllm_executor.py Outdated
def executor(fake_vllm):
executor = LocalVLLMExecutor("fake-model", {}, {})
yield executor
executor.loop.call_soon_threadsafe(executor.loop.stop)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Tests leave unfinished tasks

The executor fixture stops its loop without cancelling and awaiting pending tasks or closing the loop. Tests that call submit() leave _periodic_log sleeping when teardown runs. This can produce cleanup warnings and leave open loop resources for garbage collection.

Cancel and await pending tasks before stopping the loop, then join the thread and close the loop.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 62140b6: the fixture now cancels and awaits pending tasks, stops the loop, joins the thread and closes it (dev-mode warnings 4 → 0; vLLM tests 5/5).

…ture

The fixture only stopped the executor's loop, so `_periodic_log` was
left pending and the loop was never closed (ResourceWarning: unclosed
event loop). Cancel and await the pending tasks, stop the loop, join
its thread and close it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vLLM prompt provider hangs forever when one request fails

1 participant