Skip to content

feat(gateway): place a plain request on the cheapest card - #280

Merged
T-Crypt merged 2 commits into
nextfrom
T-Crypt/gateway-card-placement
Oct 31, 2026
Merged

T-Crypt merged 2 commits into
nextfrom
T-Crypt/gateway-card-placement

Conversation

@T-Crypt

@T-Crypt T-Crypt commented Oct 31, 2026

Copy link
Copy Markdown
Owner

Second slice of v0.5: per-card gateway endpoints.

What changes for users

When one model is served on several cards (one [[engine]] per card, since #278) and a request uses the plain /v1 URL, the gateway now picks the card. Before, it always took the first entry in berth.toml, so it could drain a busy gpu0 while gpu1 sat free, or queue behind a game.

The order is:

  1. An engine that is up and lists the model answers, as before.
  2. The card where the model's engine is parked in RAM.
  3. A free card, using the same test as background engines (cardFree): no lease, waiter, stowaway or active claim, and not in a VM.
  4. A card whose holder drains the usual way.
  5. A card a VM or a pinned lease keeps (outOfReach), where the request waits.

A tie keeps berth.toml's order. A node with one entry per model behaves exactly as before.

How

resolve collects every entry that serves the model, then takes slices.MinFunc over reach. reach ranks an entry from node.View of its card. It reuses parkedIn, cardFree and outOfReach, the helpers the gateway already uses for parked routing, background engines and the ComfyUI queue.

The roadmap's slice text now matches this order. It drops "the cheapest measured switch": the switch-cost book has no per-card data to rank on yet.

Proof

  • TestPlainRequestPicksTheCheapestCard has five cases on a two-card berthd: both cards free, a game on gpu0, a lease on gpu0, a game on gpu0 with a lease on gpu1, and qwen parked on gpu1 through a real re-attach. Three of them fail on the test-only commit.
  • Mutations: removing the parked rank fails the parked case. Merging the drainable and pinned ranks fails the game-plus-lease case.
  • TestCardBaseURLPicksTheEngineOnThatCard from feat(gateway): one base URL per card #278 still passes.
  • Build, gofmt, vet, go test ./..., the Windows build and vet, and golangci-lint (0 issues) all pass.

One model served on gpu0 and gpu1. A plain /v1 request must go to a
parked copy before a free card, a free card before one a lease holds, and
a held card before one a game pins. With nothing to tell the cards apart,
the first entry wins. Three cases fail until the gateway ranks the cards.
When several entries serve the model on different cards and no card is
named, resolve ranks each by what reaching it takes: a resume from RAM, a
free card, a drain of the holder, then a card a VM or a pinned lease
keeps. An engine that is up still answers first, and a tie keeps
berth.toml's order.

Second slice of v0.5, per-card gateway endpoints.
@T-Crypt
T-Crypt merged commit 8a9524f into next Oct 31, 2026
4 checks passed
@T-Crypt
T-Crypt deleted the T-Crypt/gateway-card-placement branch November 2, 2026 15:01
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.

1 participant