Skip to content

fix(limiter): honor runtime limit changes in local model pools - #4874

Open
ydflow wants to merge 1 commit into
Tencent:mainfrom
ydflow:fix/local-limiter-runtime-limit
Open

ydflow wants to merge 1 commit into
Tencent:mainfrom
ydflow:fix/local-limiter-runtime-limit

Conversation

@ydflow

@ydflow ydflow commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Description

After a Lite deployment first uses a model, changing model.max_concurrency does not change that model's actual local concurrency cap. The settings service updates the governor without a restart, and subsequent calls pass the new limit, but localLimiter keeps the channel capacity from its first acquire. Raising 1 to 2 still blocks the second call; lowering 2 to 1 admits a waiter as soon as either old holder releases. Runtime statistics report the new limit even while admission follows the old one.

Track the active holders and current limit under the existing limiter mutex, with a notification channel for releases and limit changes. The next acquire carrying an updated limit applies it to the existing pool and wakes waiters. Existing holders keep their release callbacks; after a decrease, new calls wait until active holders fall below the new cap. Existing waiters use the pool's updated limit when they wake rather than restoring their older argument. Preserve cancellation fail-open behavior, per-model isolation and idempotent release.

Type of Change

  • Bug fix
  • Test

Related Issue

Found during source review; no separate issue. Searched open/closed issues and PRs for localLimiter, local semaphore, dynamic concurrency, limit update and max_concurrency; no direct duplicate found. The public runtime-settings contract is documented by SetGlobalLimit and systemSettingService.applyModelMaxConcurrency.

This is independent of #4872: that PR releases a chat stream's held slot on cancellation; this PR changes local slot admission when a configured limit changes. There are no shared files or required merge order, and no changes to the Redis limiter or configuration/API schema.

Testing

Windows/amd64 with CGO enabled and existing portable GCC/G++.

  • Before the production change, the new increase/decrease regressions both fail: increasing does not admit the second holder; decreasing admits a request while an old holder is still active.
  • go test -race ./internal/models/limiter -count=10 passes on Go 1.26.0. Includes a third regression that checks an existing waiter survives a limit change and retains the updated limit.
  • go test ./internal/models/chat ./internal/models/vlm ./internal/models/limiter -count=1 passes on Go 1.27.0.
  • golangci-lint run --new-from-rev=origin/main ./internal/models/limiter/... passes with CI-pinned v2.12.2 on Go 1.26.0 (0 issues); v2.15.0 on Go 1.27.0 also passes.
  • Changed files are gofmt clean; diff whitespace check and skill freshness/account/overlap preflight pass.

No full-repository or live-provider checks were run. Local limit tests require no external services; existing package tests use miniredis for Redis behavior.

Checklist

  • git diff --check origin/main...HEAD passes
  • Changed source files are formatted
  • Targeted tests and diff-scoped lint pass
  • Self-reviewed the code
  • Added regression coverage
  • Full-repository checks were run
  • Documentation: existing runtime configuration contract is restored; no new setting
  • Breaking changes: none

Prepared with AI assistance.

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.

1 participant