Skip to content

[Router][Bugfix] Defensive fallbacks in kvaware routing: 503 on no endpoints, session/QPS on unmapped instance - #1061

Open
tyler2cr wants to merge 2 commits into
vllm-project:mainfrom
tyler2cr:router-defensive-fallbacks
Open

[Router][Bugfix] Defensive fallbacks in kvaware routing: 503 on no endpoints, session/QPS on unmapped instance#1061
tyler2cr wants to merge 2 commits into
vllm-project:mainfrom
tyler2cr:router-defensive-fallbacks

Conversation

@tyler2cr

Copy link
Copy Markdown

Two pre-existing crash paths in KvawareRouter.route_request, both turning conditions the router can survive into failed requests. Independent of #1045 and #1060 — small diff (one source file + a new test file), mergeable in any order.

1. No endpoints available → IndexError

route_request accessed endpoints[0] unguarded, so an empty endpoint list (service-discovery lag, all backends unhealthy) raised IndexError. LoadAwareRouter.route_request already answers this with HTTPException(503, "No backend endpoints available") — kvaware now mirrors it.

2. KV lookup matches an instance the ip mapping cannot place → unhandled KeyError → 500 (observed live)

QueryInstMsg keys instances by IP alone, so several engines sharing one IP (e.g. one multi-GPU host) leave all but one instance unmapped — and a stale registration produces the same shape. When the lookup then matched an unmapped instance, self.instance_id_to_ip[...] raised KeyError and the whole request failed with a 500:

    return self.instance_id_to_ip[queried_instance_ids[0]]
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 'engine0'

The router can still serve the request without the cache-hit placement, so a mapping miss now logs a warning (including the current mapping, for diagnosability) and takes the existing session/QPS fallback — the same degradation path a lookup miss takes.

(Making instance identity include the worker port — so multi-engine hosts map correctly rather than falling back — is a larger change touching the lmcache message flow; left for a follow-up. This PR just stops the crash.)

Tests

Two added, self-contained: empty endpoints → 503, unmapped instance → request served via QPS fallback (no exception). Full router suite passes (222/222).

🤖 Generated with Claude Code

…dpoints, session/QPS on unmapped instance

Two crash paths, both pre-existing:

- KvawareRouter.route_request accessed endpoints[0] unguarded - no
  available endpoints raised IndexError; LoadAwareRouter already answers
  503 for this case, kvaware now mirrors it.
- A KV lookup that matches an instance the ip mapping cannot place raised
  an unhandled KeyError and failed the request with a 500 (observed live:
  QueryInstMsg keys instances by IP alone, so several engines sharing one
  IP - e.g. one multi-GPU host - leave all but one instance unmapped; a
  stale registration does the same). The router can still serve the
  request without the cache hit, so a mapping miss now logs a warning and
  falls back to the existing session/QPS routing.

Signed-off-by: tyler <tcr@enfuse.io>

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces defensive fallbacks in KvawareRouter.route_request to handle scenarios where no endpoints are available (raising a 503 instead of an IndexError) or when a KV lookup matches an unmapped instance (falling back to session/QPS routing instead of raising a KeyError). It also adds a new test suite to verify these fallbacks. The feedback recommends removing the accidentally committed .venv/pyvenv.cfg file and refactoring the duplicated fallback logic in routing_logic.py by moving the fallback_url method to the base class KvawareRouter.

Comment thread .venv/pyvenv.cfg Outdated
Comment on lines +1 to +5
home = /opt/homebrew/opt/python@3.12/bin
include-system-site-packages = false
version = 3.12.12
executable = /opt/homebrew/Cellar/python@3.12/3.12.12/Frameworks/Python.framework/Versions/3.12/bin/python3.12
command = /opt/homebrew/opt/python@3.12/bin/python3.12 -m venv --clear /private/tmp/claude-502/-Users-enfuse-code-pvamu--claude-worktrees-prod-monitoring-alerting-research-9b4131/334ce31a-dbb3-4ec9-a7cb-f2d26c484c93/scratchpad/production-stack/.venv

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.

medium

The virtual environment configuration file .venv/pyvenv.cfg should not be committed to the repository. It contains absolute paths and settings specific to your local machine, which can cause issues for other contributors and CI/CD environments. Please remove this file from the repository and ensure that .venv/ is added to your .gitignore file.

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.

Good catch — removed in f2f255d (and .venv/ added to .gitignore so it cannot recur).

Comment on lines +477 to +481
session_id = self.extract_session_id(request, request_json)
self._update_hash_ring(endpoints)
if session_id is None:
return self._qps_routing(endpoints, request_stats)
return self.hash_ring.get_node(session_id)

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.

medium

The fallback logic implemented here is identical to the fallback logic at lines 434-444, and also matches the fallback_url method defined in LoadAwareRouter (lines 702-716). Since LoadAwareRouter inherits from KvawareRouter, we can eliminate this duplication by moving the fallback_url method up to KvawareRouter. This would allow both fallback paths in KvawareRouter.route_request to simply call self.fallback_url(endpoints, request_stats, request, request_json).

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.

Applied in f2f255dfallback_url hoisted from LoadAwareRouter up to KvawareRouter (behavior-preserving given the subclass relationship) and both kvaware fallback sites now call it. Suite 222/222.

… .venv

- fallback_url moves up from LoadAwareRouter to KvawareRouter (its
  subclass relationship makes this behavior-preserving) and both kvaware
  fallback sites - lookup miss and the new mapping miss - now call it,
  removing the triplicated session/QPS block.
- .venv/pyvenv.cfg was accidentally committed; removed and .venv/ added
  to .gitignore.

Signed-off-by: tyler <tcr@enfuse.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants