From 58f758c816c003171dd51eae6cbe0c5aed1260d9 Mon Sep 17 00:00:00 2001 From: erio Date: Fri, 3 Apr 2026 13:54:18 +0800 Subject: [PATCH] feat(channel): improve cache strategy and add restriction logging - Change channel cache TTL from 60s to 10min (reduce unnecessary DB queries) - Actively rebuild cache after CRUD instead of lazy invalidation - Add slog.Warn logging for channel pricing restriction blocks (4 places) --- backend/internal/service/channel_service.go | 9 +++++++-- backend/internal/service/gateway_service.go | 6 ++++++ backend/internal/service/openai_gateway_service.go | 6 ++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/backend/internal/service/channel_service.go b/backend/internal/service/channel_service.go index 3d607ad7..c6a249ef 100644 --- a/backend/internal/service/channel_service.go +++ b/backend/internal/service/channel_service.go @@ -133,8 +133,8 @@ func (r ChannelMappingResult) ToUsageFields(reqModel, upstreamModel string) Chan } const ( - channelCacheTTL = 60 * time.Second - channelErrorTTL = 5 * time.Second // DB 错误时的短缓存 + channelCacheTTL = 10 * time.Minute + channelErrorTTL = 5 * time.Second // DB 错误时的短缓存 channelCacheDBTimeout = 10 * time.Second ) @@ -333,6 +333,11 @@ func matchingPlatforms(groupPlatform string) []string { func (s *ChannelService) invalidateCache() { s.cache.Store((*channelCache)(nil)) s.cacheSF.Forget("channel_cache") + + // 主动重建缓存,确保 CRUD 后立即生效 + if _, err := s.buildCache(context.Background()); err != nil { + slog.Warn("failed to rebuild channel cache after invalidation", "error", err) + } } // matchWildcard 在通配符定价中查找匹配项(最先匹配到优先) diff --git a/backend/internal/service/gateway_service.go b/backend/internal/service/gateway_service.go index 14937dd4..be00e774 100644 --- a/backend/internal/service/gateway_service.go +++ b/backend/internal/service/gateway_service.go @@ -1199,6 +1199,9 @@ func (s *GatewayService) SelectAccountForModelWithExclusions(ctx context.Context // Claude Code 限制可能已将 groupID 解析为 fallback group, // 渠道限制预检查必须使用解析后的分组。 if s.checkChannelPricingRestriction(ctx, groupID, requestedModel) { + slog.Warn("channel pricing restriction blocked request", + "group_id", derefGroupID(groupID), + "model", requestedModel) return nil, fmt.Errorf("%w supporting model: %s (channel pricing restriction)", ErrNoAvailableAccounts, requestedModel) } @@ -1241,6 +1244,9 @@ func (s *GatewayService) SelectAccountWithLoadAwareness(ctx context.Context, gro // Claude Code 限制可能已将 groupID 解析为 fallback group, // 渠道限制预检查必须使用解析后的分组。 if s.checkChannelPricingRestriction(ctx, groupID, requestedModel) { + slog.Warn("channel pricing restriction blocked request", + "group_id", derefGroupID(groupID), + "model", requestedModel) return nil, fmt.Errorf("%w supporting model: %s (channel pricing restriction)", ErrNoAvailableAccounts, requestedModel) } diff --git a/backend/internal/service/openai_gateway_service.go b/backend/internal/service/openai_gateway_service.go index d1c52ea5..f12177f3 100644 --- a/backend/internal/service/openai_gateway_service.go +++ b/backend/internal/service/openai_gateway_service.go @@ -1202,6 +1202,9 @@ func (s *OpenAIGatewayService) SelectAccountForModelWithExclusions(ctx context.C func (s *OpenAIGatewayService) selectAccountForModelWithExclusions(ctx context.Context, groupID *int64, sessionHash string, requestedModel string, excludedIDs map[int64]struct{}, stickyAccountID int64) (*Account, error) { if s.checkChannelPricingRestriction(ctx, groupID, requestedModel) { + slog.Warn("channel pricing restriction blocked request", + "group_id", derefGroupID(groupID), + "model", requestedModel) return nil, fmt.Errorf("%w supporting model: %s (channel pricing restriction)", ErrNoAvailableAccounts, requestedModel) } @@ -1379,6 +1382,9 @@ func (s *OpenAIGatewayService) isBetterAccount(candidate, current *Account) bool // SelectAccountWithLoadAwareness selects an account with load-awareness and wait plan. func (s *OpenAIGatewayService) SelectAccountWithLoadAwareness(ctx context.Context, groupID *int64, sessionHash string, requestedModel string, excludedIDs map[int64]struct{}) (*AccountSelectionResult, error) { if s.checkChannelPricingRestriction(ctx, groupID, requestedModel) { + slog.Warn("channel pricing restriction blocked request", + "group_id", derefGroupID(groupID), + "model", requestedModel) return nil, fmt.Errorf("%w supporting model: %s (channel pricing restriction)", ErrNoAvailableAccounts, requestedModel) }