feat: add IncludeModelName option to channel affinity rules for per-model affinity tracking

This commit is contained in:
Clansty
2026-03-29 02:22:24 +08:00
parent fbf235d222
commit 70560d5371
3 changed files with 19 additions and 5 deletions
+17 -4
View File
@@ -166,12 +166,22 @@ func GetChannelAffinityCacheStats() ChannelAffinityCacheStats {
unknown++ unknown++
continue continue
} }
if rule.IncludeUsingGroup { if rule.IncludeModelName {
if len(parts) < 3 { if len(parts) < 3 {
unknown++ unknown++
continue continue
} }
} }
if rule.IncludeUsingGroup {
minParts := 3
if rule.IncludeModelName {
minParts = 4
}
if len(parts) < minParts {
unknown++
continue
}
}
byRuleName[ruleName]++ byRuleName[ruleName]++
} }
@@ -319,11 +329,14 @@ func extractChannelAffinityValue(c *gin.Context, src operation_setting.ChannelAf
} }
} }
func buildChannelAffinityCacheKeySuffix(rule operation_setting.ChannelAffinityRule, usingGroup string, affinityValue string) string { func buildChannelAffinityCacheKeySuffix(rule operation_setting.ChannelAffinityRule, modelName string, usingGroup string, affinityValue string) string {
parts := make([]string, 0, 3) parts := make([]string, 0, 4)
if rule.IncludeRuleName && rule.Name != "" { if rule.IncludeRuleName && rule.Name != "" {
parts = append(parts, rule.Name) parts = append(parts, rule.Name)
} }
if rule.IncludeModelName && modelName != "" {
parts = append(parts, modelName)
}
if rule.IncludeUsingGroup && usingGroup != "" { if rule.IncludeUsingGroup && usingGroup != "" {
parts = append(parts, usingGroup) parts = append(parts, usingGroup)
} }
@@ -573,7 +586,7 @@ func GetPreferredChannelByAffinity(c *gin.Context, modelName string, usingGroup
if ttlSeconds <= 0 { if ttlSeconds <= 0 {
ttlSeconds = setting.DefaultTTLSeconds ttlSeconds = setting.DefaultTTLSeconds
} }
cacheKeySuffix := buildChannelAffinityCacheKeySuffix(rule, usingGroup, affinityValue) cacheKeySuffix := buildChannelAffinityCacheKeySuffix(rule, modelName, usingGroup, affinityValue)
cacheKeyFull := channelAffinityCacheNamespace + ":" + cacheKeySuffix cacheKeyFull := channelAffinityCacheNamespace + ":" + cacheKeySuffix
setChannelAffinityContext(c, channelAffinityMeta{ setChannelAffinityContext(c, channelAffinityMeta{
CacheKey: cacheKeyFull, CacheKey: cacheKeyFull,
+1 -1
View File
@@ -193,7 +193,7 @@ func TestChannelAffinityHitCodexTemplatePassHeadersEffective(t *testing.T) {
require.NotNil(t, codexRule) require.NotNil(t, codexRule)
affinityValue := fmt.Sprintf("pc-hit-%d", time.Now().UnixNano()) affinityValue := fmt.Sprintf("pc-hit-%d", time.Now().UnixNano())
cacheKeySuffix := buildChannelAffinityCacheKeySuffix(*codexRule, "default", affinityValue) cacheKeySuffix := buildChannelAffinityCacheKeySuffix(*codexRule, "gpt-5", "default", affinityValue)
cache := getChannelAffinityCache() cache := getChannelAffinityCache()
require.NoError(t, cache.SetWithTTL(cacheKeySuffix, 9527, time.Minute)) require.NoError(t, cache.SetWithTTL(cacheKeySuffix, 9527, time.Minute))
@@ -23,6 +23,7 @@ type ChannelAffinityRule struct {
SkipRetryOnFailure bool `json:"skip_retry_on_failure,omitempty"` SkipRetryOnFailure bool `json:"skip_retry_on_failure,omitempty"`
IncludeUsingGroup bool `json:"include_using_group"` IncludeUsingGroup bool `json:"include_using_group"`
IncludeModelName bool `json:"include_model_name"`
IncludeRuleName bool `json:"include_rule_name"` IncludeRuleName bool `json:"include_rule_name"`
} }