[Bug]: engine:status re-runs the readiness probe under the engine lock on every call; a slow engine /health starves the model-list sweep and, polled ~1/s, leaked a TP=4 head to death

Đang mở
#84 2 bình luận 0 reaction 1 người được giao Xem trên GitHub

@kjlubick đang làm issue này rồi.

Từ ngày 18/9/2026.

Đánh giá

Issue này chưa được đánh giá.

Mô tả

Area

Engine or model management

User problem

Every engine:status call re-runs the engine's readiness probe while holding that engine's lifecycle lock, and several PAIR components poll status independently. On an engine whose readiness endpoint is cheap that is invisible. On an engine whose /health does real work it has two consequences we hit in production this week on a 4-node tensor-parallel SGLang head (DGX Spark, GB10):

  1. Model-list starvation. The broker's advertiser (every 5 s), the loaded-model watcher (every 5 s) and the desktop's remote status poll (every 10 s) each call engine:status. StatusAtPort takes st.opMu, then reconcilePresence runs probe(ready) and probe(identity) with no caching. SGLang's /health performs a short generation and takes ~1.0 s on this build, so the mutex was held essentially 100% of the time and ModelsResult's sweep (which needs Status first) never got in. GET :14322/v1/models on that node hung for 40 s+ indefinitely; peers piled up hundreds of CLOSE-WAIT sockets; the desktop logged remote engine status ... unavailable every 10 s. A standalone engine-manager with no broker traffic answered in 16 ms. Restarting engine-manager did not help.
  2. The probe load itself leaked memory. The head's container log shows 72,144 GET /health and 69,817 GET /get_model_info over a 20 h run, ~1/s each, with zero user requests for the final 30 min. The head's MemAvailable declined monotonically from 8.7 GB (00:20) to 2.5 GB (16:20) while the three worker ranks stayed flat, then earlyoom SIGTERMed the scheduler at 16:28 and the TP group died. After the crash the head returned to its idle baseline, so the growth was inside the front-end processes only rank 0 runs. Pointing the probes at /get_model_info (~1 ms, no generation) dropped /health traffic from ~3,500/h to the container's own healthcheck and the model list answers in 13 ms.

SGLang itself is not in develop yet (it lives in #50 and in my fork), but the mechanism is upstream code and applies to any engine whose readiness endpoint is not free; llama.cpp's /health under load and /v1/models on busy servers are candidates.

Where
  • services/nvpair-engine-manager/status.go: StatusAtPortst.opMu.Lock()reconcilePresence(context.Background(), ...)e.probe(ctx, ready, port) then e.probe(ctx, identity, port) on every call.
  • services/nvpair-engine-manager/models.go: ModelsResult calls e.Status(name) per engine before the 5 s action budget starts; the lock wait is unbounded.
  • Pollers: nvpair-ui-broker/advertiser.go (autoAdvertiseInterval = 5 * time.Second), nvpair-engine-manager/loadedwatch.go (defaultLoadedPollSeconds = 5), the desktop's remote-get-installed loop.
Proposed fix
  • Do not re-run the readiness probe for an engine that is already adopted and healthy with a live health loop; trust the health loop's last result, or cache presence for a few seconds.
  • Do not take opMu for the read-only status path; snapshot state, probe outside the lock.
  • Treat the manifest's identity endpoint as the default readiness/health probe and require an explicit opt-in for anything that generates.
Workaround for operators

A per-engine manifest override (engines/sglang.json) pointing runtime.ready.http and runtime.health.http at /get_model_info, plus the advertiser change in https://github.com/jlacroix82/Personal-AI-Router/commit/c5b9be7 (on feat/vllm-sglang).

Environment

PAIR 0.1.1 services (engine-manager 0.21.0 / broker 0.42.2 as built from feat/vllm-sglang at ff26f5b), Linux arm64, DGX Spark x4 per TP group, SGLang lmsysorg/sglang:dev-dsv41 serving DeepSeek-V4.1-Flash. Related: #37 (probe connection reuse), #50 (SGLang engine), #24 (external backends).

Ngôn ngữ chính
Go
Star
1.4k
Fork
250
Merge trung bình
23 giờ 27 phút
Pull request đã merge (30 ngày)
1

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của NVIDIA/Personal-AI-Router

Tất cả issue của NVIDIA/Personal-AI-Router

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.