(apiKey *models.APIKey, group *models.Group, keyHashKey, activeKeysListKey string)
| 186 | } |
| 187 | |
| 188 | func (p *KeyProvider) handleFailure(apiKey *models.APIKey, group *models.Group, keyHashKey, activeKeysListKey string) error { |
| 189 | keyDetails, err := p.store.HGetAll(keyHashKey) |
| 190 | if err != nil { |
| 191 | return fmt.Errorf("failed to get key details from store: %w", err) |
| 192 | } |
| 193 | |
| 194 | if keyDetails["status"] == models.KeyStatusInvalid { |
| 195 | return nil |
| 196 | } |
| 197 | |
| 198 | failureCount, _ := strconv.ParseInt(keyDetails["failure_count"], 10, 64) |
| 199 | |
| 200 | // 获取该分组的有效配置 |
| 201 | blacklistThreshold := group.EffectiveConfig.BlacklistThreshold |
| 202 | |
| 203 | return p.executeTransactionWithRetry(func(tx *gorm.DB) error { |
| 204 | var key models.APIKey |
| 205 | if err := tx.Set("gorm:query_option", "FOR UPDATE").First(&key, apiKey.ID).Error; err != nil { |
| 206 | return fmt.Errorf("failed to lock key %d for update: %w", apiKey.ID, err) |
| 207 | } |
| 208 | |
| 209 | newFailureCount := failureCount + 1 |
| 210 | |
| 211 | updates := map[string]any{"failure_count": newFailureCount} |
| 212 | shouldBlacklist := blacklistThreshold > 0 && newFailureCount >= int64(blacklistThreshold) |
| 213 | if shouldBlacklist { |
| 214 | updates["status"] = models.KeyStatusInvalid |
| 215 | } |
| 216 | |
| 217 | if err := tx.Model(&key).Updates(updates).Error; err != nil { |
| 218 | return fmt.Errorf("failed to update key stats in DB: %w", err) |
| 219 | } |
| 220 | |
| 221 | if _, err := p.store.HIncrBy(keyHashKey, "failure_count", 1); err != nil { |
| 222 | return fmt.Errorf("failed to increment failure count in store: %w", err) |
| 223 | } |
| 224 | |
| 225 | if shouldBlacklist { |
| 226 | logrus.WithFields(logrus.Fields{"keyID": apiKey.ID, "threshold": blacklistThreshold}).Warn("Key has reached blacklist threshold, disabling.") |
| 227 | if err := p.store.LRem(activeKeysListKey, 0, apiKey.ID); err != nil { |
| 228 | return fmt.Errorf("failed to LRem key from active list: %w", err) |
| 229 | } |
| 230 | if err := p.store.HSet(keyHashKey, map[string]any{"status": models.KeyStatusInvalid}); err != nil { |
| 231 | return fmt.Errorf("failed to update key status to invalid in store: %w", err) |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | return nil |
| 236 | }) |
| 237 | } |
| 238 | |
| 239 | // LoadKeysFromDB 从数据库加载所有分组和密钥,并填充到 Store 中。 |
| 240 | func (p *KeyProvider) LoadKeysFromDB() error { |
no test coverage detected