Fix loglist

This commit is contained in:
XOF
2025-11-21 19:33:05 +08:00
parent 1f7aa70810
commit 6a0f344e5c
22 changed files with 380 additions and 357 deletions

View File

@@ -11,6 +11,7 @@ import (
"io"
"sort"
"strconv"
"strings"
"time"
"gorm.io/gorm"
@@ -81,13 +82,20 @@ func (r *gormKeyRepository) SelectOneActiveKey(group *models.KeyGroup) (*models.
// SelectOneActiveKeyFromBasePool 为智能聚合模式设计的全新轮询器。
func (r *gormKeyRepository) SelectOneActiveKeyFromBasePool(pool *BasePool) (*models.APIKey, *models.KeyGroup, error) {
protocol := "default"
if pool.Protocol != "" {
protocol = string(pool.Protocol)
}
// 生成唯一的池ID确保不同请求组合的轮询状态相互隔离
poolID := generatePoolID(pool.CandidateGroups)
log := r.logger.WithField("pool_id", poolID)
poolID := generatePoolID(pool.CandidateGroups, protocol)
log := r.logger.WithField("pool_id", poolID).WithField("protocol", protocol)
if err := r.ensureBasePoolCacheExists(pool, poolID); err != nil {
log.WithError(err).Error("Failed to ensure BasePool cache exists.")
return nil, nil, err
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil, err
}
return nil, nil, fmt.Errorf("unexpected error while ensuring base pool cache: %w", err)
}
var keyIDStr string
@@ -145,25 +153,40 @@ func (r *gormKeyRepository) SelectOneActiveKeyFromBasePool(pool *BasePool) (*mod
// ensureBasePoolCacheExists 动态创建 BasePool 的 Redis 结构
func (r *gormKeyRepository) ensureBasePoolCacheExists(pool *BasePool, poolID string) error {
// 使用 LIST 键作为存在性检查的标志
listKey := fmt.Sprintf(BasePoolSequential, poolID)
exists, err := r.store.Exists(listKey)
if err != nil {
r.logger.WithError(err).Errorf("Failed to check existence of basepool key: %s", listKey)
return err
}
if exists {
val, err := r.store.LIndex(listKey, 0)
if err == nil && val == EmptyPoolPlaceholder {
if err != nil {
return err
}
if val == EmptyPoolPlaceholder {
return gorm.ErrRecordNotFound
}
return nil
}
lockKey := fmt.Sprintf("lock:basepool:%s", poolID)
acquired, err := r.store.SetNX(lockKey, []byte("1"), 10*time.Second)
if err != nil {
r.logger.WithError(err).Errorf("Failed to acquire distributed lock for basepool build: %s", lockKey)
return err
}
if !acquired {
time.Sleep(100 * time.Millisecond)
return r.ensureBasePoolCacheExists(pool, poolID)
}
defer r.store.Del(lockKey)
if exists, _ := r.store.Exists(listKey); exists {
return nil
}
r.logger.Infof("BasePool cache for pool_id '%s' not found. Building now...", poolID)
var allActiveKeyIDs []string
lruMembers := make(map[string]float64)
for _, group := range pool.CandidateGroups {
activeKeySetKey := fmt.Sprintf(KeyGroup, group.ID)
groupKeyIDs, err := r.store.SMembers(activeKeySetKey)
@@ -171,17 +194,21 @@ func (r *gormKeyRepository) ensureBasePoolCacheExists(pool *BasePool, poolID str
r.logger.WithError(err).Warnf("Failed to get active keys for group %d during BasePool build", group.ID)
continue
}
allActiveKeyIDs = append(allActiveKeyIDs, groupKeyIDs...)
for _, keyIDStr := range groupKeyIDs {
keyID, _ := strconv.ParseUint(keyIDStr, 10, 64)
_, mapping, err := r.getKeyDetailsFromCache(uint(keyID), group.ID)
if err == nil && mapping != nil {
var score float64
if mapping.LastUsedAt != nil {
score = float64(mapping.LastUsedAt.UnixMilli())
if err != nil {
if errors.Is(err, store.ErrNotFound) || strings.Contains(err.Error(), "failed to get") {
r.logger.WithError(err).Warnf("Cache inconsistency detected for KeyID %s in GroupID %d. Skipping.", keyIDStr, group.ID)
continue
} else {
return err
}
lruMembers[keyIDStr] = score
}
allActiveKeyIDs = append(allActiveKeyIDs, keyIDStr)
if mapping != nil && mapping.LastUsedAt != nil {
lruMembers[keyIDStr] = float64(mapping.LastUsedAt.UnixMilli())
}
}
}
@@ -194,23 +221,16 @@ func (r *gormKeyRepository) ensureBasePoolCacheExists(pool *BasePool, poolID str
}
return gorm.ErrRecordNotFound
}
// 使用管道填充所有轮询结构
pipe := r.store.Pipeline()
// 1. 顺序
pipe.LPush(fmt.Sprintf(BasePoolSequential, poolID), toInterfaceSlice(allActiveKeyIDs)...)
// 2. 随机
pipe.SAdd(fmt.Sprintf(BasePoolRandomMain, poolID), toInterfaceSlice(allActiveKeyIDs)...)
// 设置合理的过期时间例如5分钟以防止孤儿数据
pipe.Expire(fmt.Sprintf(BasePoolSequential, poolID), CacheTTL)
pipe.Expire(fmt.Sprintf(BasePoolRandomMain, poolID), CacheTTL)
pipe.Expire(fmt.Sprintf(BasePoolRandomCooldown, poolID), CacheTTL)
pipe.Expire(fmt.Sprintf(BasePoolLRU, poolID), CacheTTL)
if err := pipe.Exec(); err != nil {
return err
}
if len(lruMembers) > 0 {
r.store.ZAdd(fmt.Sprintf(BasePoolLRU, poolID), lruMembers)
}
@@ -226,7 +246,7 @@ func (r *gormKeyRepository) updateKeyUsageTimestampForPool(poolID string, keyID
}
// generatePoolID 根据候选组ID列表生成一个稳定的、唯一的字符串ID
func generatePoolID(groups []*models.KeyGroup) string {
func generatePoolID(groups []*models.KeyGroup, protocol string) string {
ids := make([]int, len(groups))
for i, g := range groups {
ids[i] = int(g.ID)
@@ -234,7 +254,7 @@ func generatePoolID(groups []*models.KeyGroup) string {
sort.Ints(ids)
h := sha1.New()
io.WriteString(h, fmt.Sprintf("%v", ids))
io.WriteString(h, fmt.Sprintf("protocol:%s;groups:%v", protocol, ids))
return fmt.Sprintf("%x", h.Sum(nil))
}