feat(queue): 增加非文本模型分布式准入队列

使用 PostgreSQL 统一同步与异步非文本任务的并发准入、持久化等待和 Worker 容量分配,并将生产 API 与独立 Worker 角色拆分。

补充策略管理、共享契约、OpenAPI、Kubernetes 双节点 Worker 清单及跨节点验收脚本;未默认启用任何生产 queue_size 策略。

已在原基线完成 Go、前端、迁移、Shell、Kustomize 与长任务容量验收;合入最新主干后将重新执行发布门禁。
This commit is contained in:
2026-07-29 16:15:43 +08:00
parent 2e5a90731b
commit 9e4fc7362d
55 changed files with 4565 additions and 237 deletions
+69 -1
View File
@@ -81,6 +81,74 @@ func (s *Service) rateLimitReservations(ctx context.Context, user *auth.User, ca
return out
}
func (s *Service) admissionScopes(ctx context.Context, user *auth.User, candidate store.RuntimeModelCandidate) ([]store.AdmissionScope, string) {
scopes := make([]store.AdmissionScope, 0, 2)
platformPolicy := effectiveRateLimitPolicy(candidate)
if scope, ok := admissionScopeFromPolicy(
"platform_model",
candidate.PlatformModelID,
firstNonEmptyString(candidate.DisplayName, candidate.ModelAlias, candidate.ModelName),
map[string]any{
"platformId": candidate.PlatformID,
"platformName": candidate.PlatformName,
"modelAlias": candidate.ModelAlias,
"modelName": candidate.ModelName,
},
platformPolicy,
); ok {
scopes = append(scopes, scope)
}
groupID := ""
if group, err := s.store.ResolveUserGroupPolicy(ctx, user); err == nil && group.ID != "" {
groupPolicy := store.NormalizeRateLimitPolicy(group.RateLimitPolicy)
if scope, ok := admissionScopeFromPolicy(
"user_group",
group.ID,
firstNonEmptyString(group.Name, group.GroupKey),
map[string]any{"groupKey": group.GroupKey, "name": group.Name},
groupPolicy,
); ok {
groupID = group.ID
scopes = append(scopes, scope)
}
}
return scopes, groupID
}
func admissionScopeFromPolicy(scopeType string, scopeKey string, scopeName string, metadata map[string]any, policy map[string]any) (store.AdmissionScope, bool) {
concurrentLimit, hasConcurrent := store.RateLimitPolicyMetric(policy, "concurrent")
queueRule, hasQueue := store.QueueRuleFromPolicy(policy)
if !hasConcurrent && !hasQueue {
return store.AdmissionScope{}, false
}
scope := store.AdmissionScope{
ScopeType: scopeType,
ScopeKey: scopeKey,
ScopeName: scopeName,
ScopeMetadata: metadata,
ConcurrentLimit: concurrentLimit,
Amount: 1,
LeaseTTLSeconds: 120,
Policy: policy,
}
if hasQueue {
scope.QueueLimit = queueRule.Limit
scope.MaxWaitSeconds = queueRule.MaxWaitSeconds
}
rules, _ := store.NormalizeRateLimitPolicy(policy)["rules"].([]any)
for _, rawRule := range rules {
rule, _ := rawRule.(map[string]any)
if strings.TrimSpace(stringFromMap(rule, "metric")) != "concurrent" {
continue
}
if ttl := int(floatFromAny(rule["leaseTtlSeconds"])); ttl > 0 {
scope.LeaseTTLSeconds = ttl
}
break
}
return scope, true
}
func effectiveRateLimitPolicy(candidate store.RuntimeModelCandidate) map[string]any {
return store.EffectiveRateLimitPolicy(store.EffectiveRateLimitPolicyInput{
BasePolicy: candidate.BaseRateLimitPolicy,
@@ -118,7 +186,7 @@ func reservationsFromPolicy(scopeType string, scopeKey string, scopeName string,
rule, _ := rawRule.(map[string]any)
metric := strings.TrimSpace(stringFromMap(rule, "metric"))
limit := floatFromAny(rule["limit"])
if metric == "" || limit <= 0 {
if metric == "" || metric == "queue_size" || limit <= 0 {
continue
}
amount := 1.0