Enahnce/gpustack lb policy - #6250
orangedeng wants to merge 8 commits into
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request implements a robust plugin framework for ModelRoute extensions, enabling advanced traffic management and load balancing policies. By decoupling plugin logic from the core gateway code, the system becomes more extensible. Key changes include the addition of least-load and session-affinity plugins, support for shared Redis state, and a refactoring of the AI proxy logic to be deployment-centric, ensuring more consistent and scalable gateway resource management. Highlights
New Features🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
🔍 OpenCodeReview found 10 issue(s) in this PR.
📄
|
There was a problem hiding this comment.
Code Review
This pull request introduces a modular route-plugin framework to GPUStack, adding support for load balancing, session affinity, least-load routing, and fallback paths, along with Redis configuration for shared state. The review feedback identifies several critical issues: potential ImportError exceptions from importing JSON from sqlmodel instead of sqlalchemy in the plugin schemas, a MissingGreenlet exception in model_routes.py caused by accessing lazy-loaded relationships in an async context, a failure to filter out soft-deleted targets in both the load balancer and fallback plugins, and the need to URL-decode Redis credentials to prevent authentication failures.
There was a problem hiding this comment.
Warning
- Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.
Copilot review overview
🟡 Changes recommended
Unresolved critical gateway-routing and migration issues, along with API and reconciliation defects, block approval.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 7
Open (18)
Preserve model mapping fallback when LB rules are removed · New Add LB schema in a new migration revision · New Tenant-scope target queries before plugin enrichment · New Preserve model mapper fallback when LB is unavailable · New Build LB clusters with registry-specific ports · New Normalize registry weights at the target level · New Preserve mapper fallback when LB cannot render · New Reject unvalidated reserved plugin keys in route metadata · New Enrich plugin sections in route create responses · New Wire plugin watches into reconciliation subscriptions · New Handle malformed Redis URLs without aborting startup · New Apply LB policy settings to gateway runtime · New Make policy writes participate in route transactions · New Isolate plugin factory constructor failures · New Return validation errors as client responses · New Make policy writes participate in route transactions · New Retire proxy rules for inactive or deleted targets · New Handle cold-cache delete events for reconciliation · New
What changed in this PR
This PR adds a pluggable route-plugin framework and gateway load balancing with least-load/session-affinity policies, Redis configuration, schema migrations, and AI-proxy synchronization.
Changes:
- Adds plugin registration, CRUD hooks, response enrichment, and fallback handling.
- Implements LB candidate reconciliation and gateway integration.
- Updates dependencies, API schemas, migrations, and Redis CLI/configuration.
| File | Summary |
|---|---|
uv.lock |
Updates the Higress plugin dependency lock. |
pyproject.toml |
Updates the dependency pin. |
gpustack/worker/model_file_manager.py |
Formatting cleanup. |
gpustack/websocket_proxy/proxy_server.py |
Formatting cleanup. |
gpustack/utils/task.py |
Formatting cleanup. |
gpustack/utils/gpu.py |
Formatting cleanup. |
gpustack/server/server.py |
Adjusts gateway cleanup integration. |
gpustack/server/controllers.py |
Adds plugin reconciliation and AI-proxy synchronization. |
gpustack/schemas/model_routes.py |
Adds LB fields and plugin payloads. |
gpustack/routes/plugins/session_affinity/schemas.py |
Adds session-affinity schemas. |
gpustack/routes/plugins/session_affinity/plugin.py |
Implements session-affinity hooks and capability handling. |
gpustack/routes/plugins/session_affinity/config.py |
Adds session-affinity configuration. |
gpustack/routes/plugins/session_affinity/__init__.py |
Exposes the session-affinity plugin. |
gpustack/routes/plugins/registry.py |
Adds plugin discovery and dispatch. |
gpustack/routes/plugins/least_load/schemas.py |
Adds least-load schemas. |
gpustack/routes/plugins/least_load/plugin.py |
Implements least-load policy hooks. |
gpustack/routes/plugins/least_load/config.py |
Adds least-load configuration. |
gpustack/routes/plugins/least_load/__init__.py |
Exposes the least-load plugin. |
gpustack/routes/plugins/lb/schemas.py |
Adds LB schemas. |
gpustack/routes/plugins/lb/reconciler.py |
Reconciles LB candidates and gateway rules. |
gpustack/routes/plugins/lb/plugin.py |
Integrates LB policy and capability handling. |
gpustack/routes/plugins/lb/gateway.py |
Generates LB gateway resources. |
gpustack/routes/plugins/lb/config.py |
Adds LB configuration. |
gpustack/routes/plugins/lb/capability.py |
Adds LB capability support. |
gpustack/routes/plugins/lb/__init__.py |
Exposes the LB plugin. |
gpustack/routes/plugins/fallback/plugin.py |
Adds fallback routing behavior. |
gpustack/routes/plugins/fallback/__init__.py |
Exposes the fallback plugin. |
gpustack/routes/plugins/base.py |
Defines the plugin framework base. |
gpustack/routes/plugins/artifacts.py |
Collects plugin gateway artifacts. |
gpustack/routes/plugins/__init__.py |
Initializes the plugin package. |
gpustack/routes/model_routes.py |
Integrates plugin CRUD and response handling. |
gpustack/migrations/versions/2026_09_11_1000-f1a2b3c4d5e6_v2_3_0_rc1_post_database_changes.py |
Adds LB and plugin schema changes. |
gpustack/migrations/versions/2026_09_11_1000-f1a2b3c4d5e6_usage_details_request_ids_and_ttft.py |
Updates the usage-details migration bundle. |
gpustack/gateway/utils.py |
Changes mapper and AI-proxy reconciliation. |
gpustack/gateway/__init__.py |
Publishes plugin gateway resources and Redis registries. |
gpustack/config/config.py |
Adds Redis configuration. |
gpustack/cmd/start.py |
Adds Redis CLI and environment wiring. |
Files excluded by content exclusion policy (13)
- tests/gateway/test_ai_proxy_model_grouping.py
- tests/gateway/test_gateway_plugins.py
- tests/gateway/test_gateway_utils.py
- tests/routes/plugins/init.py
- tests/routes/plugins/capabilities/init.py
- tests/routes/plugins/capabilities/test_capability_plugins.py
- tests/routes/plugins/fallback/init.py
- tests/routes/plugins/fallback/test_fallback.py
- tests/routes/plugins/lb/init.py
- tests/routes/plugins/lb/test_lb.py
- tests/routes/plugins/test_artifacts.py
- tests/routes/plugins/test_registry.py
- tests/server/test_route_ai_proxy_grouping.py
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
|
/gpustack-code-review |
Introduce a plugin framework for model-route gateway concerns: a base plugin interface, a registry that discovers and orders plugins, and a declarative artifact/rule collector that plugins use to declare the matchRules and gateway entries they own instead of writing them behind each other
Move the mapper fallback path out of the generic gateway writer into a route plugin that declares its own matchRules via the rule collector, and reconcile the route gateway when fallback codes change
The lb plugin derives the load-balancing mode from route annotations, excludes fallback targets from candidates, keeps the ingress alive for all-zero-weight routes, and owns its gateway entries via the rule collector. Wire --redis-url for its shared-state backend, bump gpustack-higress-plugins, and batch per-route plugin reconcile in the model controller
…el names on the mapper CR Build ai-proxy entries per deployment from every referencing route with service-only match rules, route model names through the mapper CR instead of alias services, and stop the mapper and LB writers from deleting each other
…_rc1 bundle The standalone usage-details revision is unreleased, so its changes belong in the current release bundle revision instead of a separate file
cf54d85 to
51f5586
Compare
|
/gpustack-code-review |
There was a problem hiding this comment.
Warning
- Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.
Copilot review overview
🟡 Changes recommended
Unresolved critical and moderate issues remain in reconciliation, plugin state handling, fallback routing, and gateway security.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 11
Open (24)
Metadata updates silently delete hidden plugin state · New Created model targets do not trigger ai-proxy reconciliation · New Missing capability incorrectly creates an empty WasmPlugin · New Redis credentials are exposed in WasmPlugin specs · New Fallback mapper removes required legacy model mappings · New Model ID history values are not unwrapped before set insertion · New Preserve mapper fallback when LB cannot render Normalize registry weights at the target level Build LB clusters with registry-specific ports Tenant-scope target queries before plugin enrichment Preserve model mapping fallback when LB rules are removed Set-fallback response omits target plugin sections · New Static Redis URLs incorrectly default to port 80 · New Plugin deletion commits outside the route transaction · New Plugin deletion commits outside the route transaction · New Handle cold-cache delete events for reconciliation Retire proxy rules for inactive or deleted targets Make policy writes participate in route transactions Return validation errors as client responses Make policy writes participate in route transactions
And 4 more that still need to be addressed.
Resolved since last review (4)
Files excluded by content exclusion policy (14)
- tests/gateway/test_ai_proxy_model_grouping.py
- tests/gateway/test_gateway_plugins.py
- tests/gateway/test_gateway_utils.py
- tests/routes/plugins/init.py
- tests/routes/plugins/capabilities/init.py
- tests/routes/plugins/capabilities/test_capability_plugins.py
- tests/routes/plugins/fallback/init.py
- tests/routes/plugins/fallback/test_fallback.py
- tests/routes/plugins/lb/init.py
- tests/routes/plugins/lb/test_lb.py
- tests/routes/plugins/test_artifacts.py
- tests/routes/plugins/test_registry.py
- tests/server/test_changed_scalar.py
- tests/server/test_route_ai_proxy_grouping.py
51f5586 to
f459476
Compare
f459476 to
cb53763
Compare
cb53763 to
2efbf3d
Compare
2efbf3d to
e0b0420
Compare
e0b0420 to
fcc8d3b
Compare
fcc8d3b to
f388602
Compare
f388602 to
13c881e
Compare
Plugin section handling and response shape: - route responses carry plugin sections with derived storage keys stripped, so a client round-tripping them cannot re-persist or delete stored policies; an explicit meta update preserves plugin-owned keys from the existing row - enqueue the ai-proxy reconcile for created model targets on both creation paths (they carry no UPDATED event of their own) - enrich the /set-fallback response with target plugin sections - surface a malformed plugins section as 400 instead of 500 Gateway and reconcile: - make ai-proxy candidate cluster names carry the registry real port (dns instance registries and provider registries do not use 80) - refuse credentialed redis urls instead of materializing the password in the WasmPlugin CR; default the static registry domain to 6379 - gate lb candidate rendering on the gpustack-lb module actually resolving, so the degraded plain-mapper CR keeps the legacy rewrite - skip creating a WasmPlugin whose spec no owner can author - publish the gpustack-model-mapper CR unconditionally so model-name rewrite works on a fresh cluster Storage and events: - move the lb schema to its own migration revision, ordered after the usage-details revision - hard-delete capability policy rows inside the caller transaction (unique route_id + soft delete broke remove-then-re-add) - reject an empty sessionKeys chain; keep plugin-named keys in model meta from forging route plugin state - normalize changed-field scalars (tuple or list shaped) across both event paths so model_id change notifications carry real ids
13c881e to
faf44e4
Compare
Refer to issues: