Skip to content

feat: reranking concurrency gate, total deadline, and 512-passage nemotron batches - #2566

Closed
erichare wants to merge 3 commits into
mainfrom
feat/reranker-concurrency-gate
Closed

feat: reranking concurrency gate, total deadline, and 512-passage nemotron batches#2566
erichare wants to merge 3 commits into
mainfrom
feat/reranker-concurrency-gate

Conversation

@erichare

Copy link
Copy Markdown
Contributor

What this does

PepsiCo needs 1000 simultaneous findAndRerank requests to succeed without errors (latency may grow). Today each request fans out ceil(passages/10) concurrent rerank POSTs with no concurrency limit anywhere, so a 1000-request burst is ~10,000 concurrent calls; the reranking NIM's internal queue blows past the read timeout and requests mass-fail with RERANKING_PROVIDER_TIMEOUT.

Queuing alone converts errors into latency but does not create throughput, so this PR combines three things:

1. Reranking concurrency gate (per provider+model, per pod)

  • Per-pod bulkhead: at most max-concurrent-calls (default 32) rerank calls in flight across all requests; excess calls park in a bounded FIFO queue (max-queued-calls, default 1000). New non-blocking RerankingConcurrencyGate + @ApplicationScoped RerankingConcurrencyGateRegistry (providers are constructed per request, so shared state must live in a singleton).
  • Queue overflow fails fast with the new RERANKING_PROVIDER_OVERLOADED error, without ever calling the provider — and it is deliberately never retried (retrying a saturation rejection deepens the overload).
  • Per-request fan-out cap: max-concurrent-batches (default 8) via Uni.join().usingConcurrencyOf().
  • Total deadline: total-timeout-millis (default 30000) covers queue wait + all batches + retries. Expiry surfaces RERANKING_PROVIDER_TIMEOUT; parked work is abandoned before it reaches the provider. The embedding-gateway path inherits the gate and deadline through the RerankingProvider base class — previously the gRPC path had no client-side time bound at all.
  • Metrics per provider+model: rerank.all.queue.depth, rerank.all.inflight.calls (gauges), rerank.all.queue.wait.duration (timer, parked grants), rerank.all.queue.rejected.count (counter).

2. nemotron rerank model with 512-passage batches

nvidia/llama-3.2-nemoretriever-500m-rerank-v2 (max-batch-size: 512, non-default) collapses a typical findAndRerank from 10 rerank calls to 1 — the lever that makes the 1000-burst arithmetically feasible (PepsiCo's own 2-pod nemotron benchmark absorbed an 1800-request burst at 0% errors).

3. Config plumbing + handoff docs

  • New properties flow through RequestProperties, the yaml schema, and embedding_gateway.proto (optional fields 7–10). Unset or out-of-range gateway values fall back to the Data API defaults, never zero, so the Data API can deploy before EGW.
  • CONFIGURATION.md gains a Reranking configuration section (there was none).
  • docs/reranking-nim-capacity-recommendations.md: gpu-helm-charts changes (nemotron NIM deployment, ingress route, NIM_SERVER_MAX_QUEUE_SIZE / NIM_SERVER_REQUEST_TIMEOUT_S, replica sizing formula).
  • docs/reranking-egw-coordination.md: EGW proto mirror + serving nemotron with batch 512 for Astra.

Behavior changes to note

  • Enabled by default with generous limits: steady-state traffic never queues (well below 32 in-flight/pod); only true bursts change behavior, which is the point.
  • Requests with >8 batches (>80 passages on the batch-10 model) serialize past the fan-out cap — bounded latency increase, no errors.
  • New terminal error code RERANKING_PROVIDER_OVERLOADED (clients should treat as retry-later).
  • The EGW path gains a client-side total deadline (intentional gap closure).

Test plan

  • RerankingConcurrencyGateTest (9): cap enforcement incl. multi-threaded contention, FIFO order, no barging, overflow fail-fast (work never invoked), cancel-while-parked frees the slot, release on failure/cancellation, meter tracking
  • RerankingProviderTest (+6): fan-out cap with correct aggregation, shared gate across provider instances, deadline-while-parked (provider never called, queue drained), deadline mid-call releases permit, overflow surfaced to caller, OVERLOADED never retried / TIMEOUT still retried
  • RerankingProvidersConfigTest / ...OverrideTest / RerankingProviderConfigProducerTest: yaml defaults, per-deployment overrides, EGW proto pass-through + fallback semantics (incl. explicit max_queued_calls=0 honored)
  • AllErrorCodesLoadTest covers the new error template
  • Full unit suite: 3487 tests, 0 failures
  • Integration test run (DSE via colima) — FindRerankingProvidersIntegrationTest expectations updated for the new model entry
  • Burst load test on the dev GPU plane (rerank-loadtest, 1000-request burst): expect queueing not rejection at defaults, OVERLOADED only beyond the configured envelope
  • Confirm nemotron ingress route + model id against the gpu-helm-charts deployment before cutover (route is projected; documented in the capacity recommendations doc)

…l deadline

A 1000-request findAndRerank burst currently fans out ~10 concurrent rerank
calls per request with no limit anywhere, overrunning the reranking NIM's
queue and mass-failing on the read timeout. This adds a per provider+model
concurrency gate so bursts degrade into orderly queueing instead of a
thundering herd:

- RerankingConcurrencyGate: non-blocking bulkhead capping in-flight rerank
  calls per pod (max-concurrent-calls, default 32) with a bounded FIFO wait
  queue (max-queued-calls, default 1000). Overflow fails fast with the new
  RERANKING_PROVIDER_OVERLOADED error without calling the provider, and is
  deliberately never retried. Cancellation while parked frees the queue slot
  without consuming a permit.
- Per-request fan-out cap via Uni.join().usingConcurrencyOf()
  (max-concurrent-batches, default 8).
- Total per-request deadline (total-timeout-millis, default 30000) covering
  queue wait, all batches, and retries; expiry surfaces
  RERANKING_PROVIDER_TIMEOUT and abandons parked work before it reaches the
  provider.
- Providers are constructed per API request, so gates live in the new
  @ApplicationScoped RerankingConcurrencyGateRegistry and are passed through
  the RerankingProvider base constructor; the embedding gateway path
  (RerankingEGWClient) inherits the gate and deadline, which also closes the
  previously-unbounded gRPC path.
- New properties flow through RequestProperties, the yaml schema, and
  embedding_gateway.proto (optional fields 7-10) with unset/out-of-range
  values falling back to the Data API defaults, never zero.
- Micrometer meters per gate: rerank.all.queue.depth, rerank.all.inflight.calls,
  rerank.all.queue.wait.duration, rerank.all.queue.rejected.count.
nvidia/llama-3.2-nemoretriever-500m-rerank-v2 (NIM 2.x) accepts 512 passages
per call, so a typical findAndRerank becomes a single reranking call instead
of a fan-out of ten batch-10 calls - the main throughput lever for absorbing
large request bursts. Non-default; the legacy rerankqa-1b-v2 model and the
default /nvidia/v1/ranking route are unchanged.

The model URL uses the per-model ingress route pattern; the corresponding
GPU-plane deployment and route are tracked in
docs/reranking-nim-capacity-recommendations.md. On embedding-gateway
deployments the served model list comes from the gateway, which needs the
matching entry (docs/reranking-egw-coordination.md).
…otes

- CONFIGURATION.md: new Reranking configuration section documenting the
  per-model properties including the concurrency gate knobs, the queue sizing
  rule, and the gate metrics.
- docs/reranking-nim-capacity-recommendations.md: gpu-helm-charts side of the
  1000-burst target - nemotron NIM deployment, ingress route, NIM 2.x queue
  and shedding env vars, and the replica sizing formula.
- docs/reranking-egw-coordination.md: embedding gateway proto fields to
  mirror (7-10), fallback semantics, and the requirement to serve the
  nemotron model with max_batch_size 512 for Astra.
@github-actions

Copy link
Copy Markdown
Contributor

📈 Unit Test Coverage Delta vs Main Branch

Metric Value
Main Branch 53.44%
This PR 53.73%
Delta 🟢 +0.29%
✅ Coverage improved!

@github-actions

Copy link
Copy Markdown
Contributor

Unit Test Coverage Report

Overall Project 53.73% -0.12% 🍏
Files changed 80.53% 🍏

File Coverage
RerankingProviderException.java 100% 🍏
RerankingConcurrencyGate.java 96.59% -3.41% 🍏
RerankingProvidersConfigImpl.java 83.64% 🍏
RerankingEGWClient.java 81.32% 🍏
RerankingProviderConfigProducer.java 72.17% 🍏
RerankingProvider.java 65.28% 🍏
RerankingProvidersConfig.java 34.43% 🍏
NvidiaRerankingProvider.java 18.07% 🍏
RerankingProviderFactory.java 6.93% -5.45%
RerankingConcurrencyGateRegistry.java 0%

@erichare

Copy link
Copy Markdown
Contributor Author

Closing — this bundles too much for one review. Splitting into smaller PRs: (1) the nemotron 512-passage model entry, (2) a total reranking deadline, (3) the concurrency gate. Branch feat/reranker-concurrency-gate is retained as the reference implementation.

@github-actions

Copy link
Copy Markdown
Contributor

📉 Integration Test Coverage Delta vs Main Branch (dse69-it)

Metric Value
Main Branch 71.44%
This PR 71.18%
Delta 🔴 -0.27%
⚠️ Coverage decreased

@github-actions

Copy link
Copy Markdown
Contributor

Integration Test Coverage Report (dse69-it)

Overall Project 71.18% -0.45% 🍏
Files changed 29.35%

File Coverage
RerankingProvidersConfig.java 98.36% 🍏
RerankingConcurrencyGateRegistry.java 74.77% -25.23% 🍏
RerankingProviderFactory.java 45.05% 🍏
RerankingProviderConfigProducer.java 27.83% -14.49%
RerankingConcurrencyGate.java 24.33% -75.67%
RerankingProvidersConfigImpl.java 21.82% -15.45%
NvidiaRerankingProvider.java 13.25% 🍏
RerankingProvider.java 12.66% -13.76%
RerankingEGWClient.java 0% -2.75%
RerankingProviderException.java 0% -15.79%

@github-actions

Copy link
Copy Markdown
Contributor

📉 Integration Test Coverage Delta vs Main Branch (hcd-it)

Metric Value
Main Branch 72.76%
This PR 72.49%
Delta 🔴 -0.27%
⚠️ Coverage decreased

@github-actions

Copy link
Copy Markdown
Contributor

Integration Test Coverage Report (hcd-it)

Overall Project 72.49% -0.45% 🍏
Files changed 29.35%

File Coverage
RerankingProvidersConfig.java 98.36% 🍏
RerankingConcurrencyGateRegistry.java 74.77% -25.23% 🍏
RerankingProviderFactory.java 45.05% 🍏
RerankingProviderConfigProducer.java 27.83% -14.49%
RerankingConcurrencyGate.java 24.33% -75.67%
RerankingProvidersConfigImpl.java 21.82% -15.45%
NvidiaRerankingProvider.java 13.25% 🍏
RerankingProvider.java 12.66% -13.76%
RerankingEGWClient.java 0% -2.75%
RerankingProviderException.java 0% -15.79%

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