router: pin video generation to a capable engine (never the gguf-only sibling)

Two bugs let a torch video pipeline run on the nvidia-gguf engine (caps={"gguf"})
when the nvidia engine was briefly down mid-restart:

1. _INFERENCE_PATHS listed "/v1/videos/generations" (plural) but the endpoint is
   "/v1/video/generations" (singular, video.py:3104). So video requests failed
   is_inference_path(), skipped all capability-aware routing, and fell through to
   registry.primary() — which returns the first HEALTHY engine when the primary
   (nvidia) is unhealthy, i.e. the gguf sibling. Fixed the path.

2. pick_engine() step 5 fell back to a capability-BLIND least_loaded(None) pick,
   so a typed request could still land on an engine lacking the capability. Now a
   typed request (transformers/gguf/whisper) only ever picks a capable engine —
   preferring the primary when it can serve the cap (request queues / caller
   retries), else 503 — instead of mis-routing to an incompatible engine.

Net: video generation (cap=transformers) routes to the nvidia engine only; if it
is busy it queues there, if it is restarting the caller retries — it never runs a
torch pipeline on the gguf-only engine. Bumps to 0.1.30.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
parent ff39ee42
......@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here.
__version__ = "0.1.29"
__version__ = "0.1.30"
# Configure the CUDA caching allocator BEFORE torch is imported anywhere.
# expandable_segments lets the allocator return freed pages to the driver even
......
......@@ -33,7 +33,7 @@ _INFERENCE_PATHS = {
"/v1/images/edits",
"/v1/audio/speech",
"/v1/audio/transcriptions",
"/v1/videos/generations",
"/v1/video/generations",
}
......@@ -170,10 +170,22 @@ def pick_engine(registry: EngineRegistry, path: str, method: str,
if e and e.healthy and e.can_serve(cap):
return e
# 5. Least-loaded compatible engine; then any engine rather than 503.
return (registry.least_loaded(cap)
or registry.least_loaded(None)
or registry.primary())
# 5. Least-loaded compatible engine. A capability-BLIND fallback
# (least_loaded(None)) is permitted ONLY for a request that needs no
# specific capability — a TYPED request (`transformers` video/image,
# `gguf`, `whisper`, …) must never run on an engine that lacks that
# capability. Otherwise the torch/GGUF process isolation breaks: when the
# nvidia (transformers) engine is briefly down mid-restart, a video request
# would otherwise land on the gguf-only sibling and run a torch pipeline
# there. Instead prefer the primary when IT can serve the cap (the request
# queues there / the caller retries as it comes back), else 503.
best = registry.least_loaded(cap)
if best is not None:
return best
if cap is None:
return registry.least_loaded(None) or registry.primary()
prim = registry.primary()
return prim if (prim is not None and prim.can_serve(cap)) else None
# Admin/auth/config/UI and everything else → primary (consistent sessions).
return registry.primary() or registry.least_loaded()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment