mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-19 05:47:48 +00:00
feat(limits): unconditional usage accounting
buildLimitScopes previously omitted a user or group scope entirely whenever that entity had no configured Limits, so a limit-less user/group never accumulated ANY usage counters. Root-caused live: the admin dashboard's total kept climbing while every per-user row stayed zero until an operator added phantom, unreachable requestsPerDay limits everywhere just to make counters build at all. buildLimitScopes now always builds a user and a group scope. Limits still gate enforcement only: evaluateScope already no-ops on a nil Limits field, so a limit-less scope is counted but never violates. Update stale doc comments coupling accounting to configured limits (evaluateScope, the integration alice fixture, routes_media_test.go, routes_unified_test.go, admin_test.go's admin1 assertion) and add: - TestBuildLimitScopes_AlwaysBuildsBothScopes: table-driven over every nil/non-nil user/group limits combination. - TestAdminUsage_LimitlessUserAndGroup_AccumulateRealTraffic: end-to-end regression proving a limit-less user and group accumulate real request/token counters visible via GET /admin/api/usage.
This commit is contained in:
@@ -860,14 +860,15 @@ func (l *limiter) checkAndCount(scopes []limitScope) *limitViolation {
|
||||
|
||||
// evaluateScope checks one scope's already-set limits against its
|
||||
// just-incremented request counts and its accumulated token/cost counts.
|
||||
// A nil limits field means nothing to evaluate for this scope. In
|
||||
// principle a nil-limits scope can still reach here with its req counters
|
||||
// already incremented by checkAndCount, since that increment runs before
|
||||
// any evaluation; in practice the unified route's buildLimitScopes
|
||||
// (routes_unified.go, ruling e) never builds one — it omits a user or
|
||||
// group scope from the slice entirely whenever that scope's own limits
|
||||
// are nil — so this check is a defensive no-op today, not a path any
|
||||
// current caller exercises.
|
||||
// A nil limits field means nothing to evaluate for this scope — the real,
|
||||
// commonly-exercised path since the v0.21 accounting fix: buildLimitScopes
|
||||
// (routes_unified.go) now ALWAYS builds a user and a group scope, so a
|
||||
// limit-less user or group reaches here on every request, with its req
|
||||
// counters already incremented by checkAndCount (that increment runs before
|
||||
// any evaluation) and nothing for this function to enforce against them.
|
||||
// This is exactly the mechanism that decouples accounting from
|
||||
// enforcement: the scope is counted unconditionally, evaluated only when it
|
||||
// actually has a limit configured.
|
||||
func (l *limiter) evaluateScope(sc limitScope, minCount, dayCount int64, now time.Time) *limitViolation {
|
||||
if sc.limits == nil {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user