Skip to content

[ISSUE #8254] Add tenant and model scoped concurrency admission for AI proxy traffic - #8440

Open
konlue wants to merge 1 commit into
apache:masterfrom
konlue:feat/8254-concurrency-admission
Open

konlue wants to merge 1 commit into
apache:masterfrom
konlue:feat/8254-concurrency-admission

Conversation

@konlue

@konlue konlue commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #8254.

Problem

The AI transport pool bounds TCP connections process-wide, but a connection pool is not request admission: one tenant streaming long answers can occupy the pool's capacity regardless of who else is waiting, and nothing distinguishes a trusted tenant from anonymous traffic when the gateway is saturated. This adds the first delivery of #8254: opt-in per-gateway concurrency admission with trusted-tenant and model-pool in-flight caps, finite bounded waiting inside the shared request deadline, and deterministic FIFO queue discipline — fixed caps, no adaptive control, no distributed quota claims.

Approach

Two independent pool dimensions gate an invocation, with separate ownership. The logical permit lives in the trusted-tenant pool: acquired once per invocation from the authenticated AgentRequestContext (anonymous traffic shares one pool; the identity never comes from wire metadata), held across retries, fallbacks and repairs, and released exactly once at the terminal signal. The target permit lives in the model pool: acquired per attempt against the effective model — now carried on the prepared exchange instead of re-parsed from the upstream body — and released when that attempt ends; for a streaming response that is body completion, error or cancellation, so backoff between attempts holds no target capacity and a fallback attempt keys on the fallback model.

Each pool is a fair semaphore with a finite waiting bound; arrivals beyond the bound are rejected immediately, and the effective wait is the smaller of the configured maximum and the shared-deadline remainder, so time already queued counts against requestDeadline — the 3 s/2.8 s primary scenario cannot grant a fresh 5 s allowance. Every permit decision runs at subscription time, never at assembly, so a retry attempt observes its predecessor's release. Waiting happens off the event loop on the bounded-elastic scheduler, bounded by the waiting limits. The pool map is hard-capped and the in-flight/waiting gauges aggregate per pool in-process — raw tenants and models are never exported as metric labels.

Rejections happen before any upstream call: a waiting-bound overflow or an expired wait surfaces as 429 TOO_MANY_REQUESTS with distinct attempt-event reasons (ADMISSION_REJECTED, ADMISSION_WAIT_DEADLINE_EXCEEDED) and the terminal observation as RATE_LIMITED. With the feature disabled the gateway holds no admission state and behaves byte-identically to today; the admission component only exists when shenyu.plugins.ai.proxy.admission.enabled=true, and a misconfigured bound fails fast.

Testing

Deterministic tests cover the pool semantics (acquire/release restoring the pool, immediate rejection at a full pool without a waiting bound, the full waiting bound rejecting the third arrival while the holder keeps its permit, a waiter admitted on release, an expired deadline rejecting before any waiting, anonymous sharing, independent tenant and model pools, the pool-map cap, unknown-pool release as a no-op, fail-fast bounds) and the orchestration (a full tenant pool rejecting without any upstream call, the 429 mapping, retry re-acquiring the target permit with both pools restored at the terminal signal, the model pool capping attempts from different tenants, cancellation releasing both held permits). All are sleep-free; timing-sensitive release assertions use bounded awaitility.

shenyu-plugin-ai-proxy 526 tests (16 new), shenyu-spring-boot-starter-plugin-ai-proxy 22, shenyu-common 711 (4 skipped) — all green; Checkstyle clean. The two-pool ownership table, deadline semantics and layering against the Netty transport pool are documented in shenyu-plugin-ai/AI_CONCURRENCY_ADMISSION.md.

This branch has not been deployed

No deployments
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.

[Task][AI Proxy] Add tenant/model-scoped concurrency admission and bounded queueing

1 participant