ollama-proxy: add opt-in late binding - #76
Open
sabbasizadeh wants to merge 1 commit into
Open
sabbasizadeh wants to merge 1 commit into
sabbasizadeh wants to merge 1 commit into
Conversation
The proxy picks a node when a request arrives and forwards it at once, so a request can wait behind a busy node while another node sits idle. --late-binding (off by default) holds a request until some node has a free generation slot, then makes the existing least-loaded choice among the free nodes. --node-parallel sets the slots per node; it should match each engine's OLLAMA_NUM_PARALLEL. Occupancy is the proxy's own ledger of requests it has bound and not yet seen finish. The scheduler's pending count still orders the choice but does not gate it: it arrives a full round trip late, so it would count a request twice and keep a finished one occupying its node. A waiting request is announced with workload:submitted (queued, no node) and re-pointed by workload:started once bound. The wait is bounded by a timer and the request context; on expiry the request commits exactly as it does today. The ledger assumes this proxy is the node's only client, which PAIR's layout ensures. With the flag unset, routing and the event stream are unchanged. Bumps ollama-proxy 0.26.2 -> 0.27.0 and product/installer 0.91.7 -> 0.92.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Sepehr Abbasi Zadeh <1991940+sabbasizadeh@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
ollama-proxychooses a node when a request arrives and forwards it immediately, so arequest can wait behind a busy node while another node sits idle.
--late-binding(off bydefault) holds the request until some eligible node has a free generation slot, then makes
the existing least-loaded choice among the free nodes.
--node-parallelsets slots per node (N, or<node-id>=N); match each engine'sOLLAMA_NUM_PARALLEL.The scheduler's
pendingstill orders the choice; it does not gate it.workload:submitted(queued, noscheduledOn);workload:startedre-points the same id at the node that runs it.nvpair-job-scheduler, the priority contract and all JSON-RPC payloads are unchanged.With the flag off, routing and the event stream are unchanged.
Results
1x RTX 5090 + 2x GB10, one Ollama 0.34.0 engine each,
qwen3.6:35b-a3b,OLLAMA_NUM_PARALLEL=1(the resolved default). Workload: 5 independent chains of 5 dependentcalls (25 calls, 5 in flight). Six rounds with the three arms interleaved; medians shown.
--late-binding --node-parallel 1Late binding vs. PAIR: 1.23x per token, 1.22x makespan.
Scope
In:
services/ollama-proxy(flags, slot gate, bounded wait, release on the terminalworkload transition,
workload:submittedfor a waiting request), tests, the ollama-proxyREADME, one limitation paragraph in
docs/architecture.mdx,services/versions.json.Out:
lmstudio-proxy(the same change applies; held until you want the approach),exposing the flag through the broker/desktop, moving a reservation on failover, and making
the wait budget a flag.
Validation
Go 1.27.0, clean checkout of this branch:
go test ./...is also green inshared,nvpair-job-schedulerandnvpair-workload-manager. Two tests fail identically onmainon macOS:TestAliasSelfTargetMatchesBoundLoopbackAddressNotPortAlonein ollama-proxy (127.0.0.2 is notbound by default) and
TestConfiguredLMStudioProxyPortinnvpair-ui-broker(its isolationsets
XDG_CONFIG_HOME, whichos.UserConfigDirignores on macOS, so it reads the port a localPAIR install persisted). Desktop gates were not run (no
desktop/node_modules); the change addsno JSON-RPC method or payload.
New tests in
services/ollama-proxy/latebind_test.go:TestLateBindingOff_CommitsToTheLeastLoadedNodeAndNeverWaits,TestLateBindingOff_NeverAnnouncesAQueuedWorkload,TestLateBinding_PrefersAFreeNodeOverALowerLoadedFullOne,TestLateBinding_WaitsForAReleasedSlot,TestLateBinding_AReleasedSlotIsFreeWithoutWaitingForTheScheduler,TestLateBinding_ASnapshotDoesNotFreeASlotThatIsStillGenerating,TestLateBinding_SnapshotWakesAWaitingRequest,TestLateBinding_CancelledRequestStopsWaiting,TestLateBinding_WaitBudgetFallsBackToImmediateCommit,TestLateBinding_ConcurrentBurstNeverExceedsCapacity,TestLateBinding_HandleHTTPHoldsTheSecondRequestUntilTheFirstFinishes,TestLateBinding_AQueuedRequestIsAnnouncedThenRepointedAtItsNode,TestNodeParallelFlags_ParsesDefaultsAndPerNodeOverrides.Risk
verbatim into
pickCandidateLocked, behind a nil check.sync.Condover the mutexreserveCandidatealready holds; every waker takes that mutex before broadcasting; thewait is bounded by a timer and by the request context (client disconnect, shutdown).
which PAIR's layout ensures; stated in
latebind.goand the README.ollama-proxy0.26.2 → 0.27.0;product/installer0.91.7 → 0.92.0.Checklist
git commit -s), certifying the Developer Certificate of Origin.services/ollama-proxy/README.md,docs/architecture.mdx).services/versions.json, and described user-visible changes above so they reach the release notes.