Skip to content

Commit 9678be7

Browse files
committed
feat: add DisableCooling configuration to manage quota cooldown behavior
1 parent 243bf5c commit 9678be7

File tree

5 files changed

+40
-3
lines changed

5 files changed

+40
-3
lines changed

cmd/server/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/router-for-me/CLIProxyAPI/v6/internal/usage"
2828
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
2929
sdkAuth "github.com/router-for-me/CLIProxyAPI/v6/sdk/auth"
30+
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
3031
log "github.com/sirupsen/logrus"
3132
)
3233

@@ -377,6 +378,7 @@ func main() {
377378
}
378379
}
379380
usage.SetStatisticsEnabled(cfg.UsageStatisticsEnabled)
381+
coreauth.SetQuotaCooldownDisabled(cfg.DisableCooling)
380382

381383
if err = logging.ConfigureLogOutput(cfg.LoggingToFile); err != nil {
382384
log.Fatalf("failed to configure log output: %v", err)

internal/api/server.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
233233
s.oldConfigYaml, _ = yaml.Marshal(cfg)
234234
s.applyAccessConfig(nil, cfg)
235235
managementasset.SetCurrentConfig(cfg)
236+
auth.SetQuotaCooldownDisabled(cfg.DisableCooling)
236237
// Initialize management handler
237238
s.mgmt = managementHandlers.NewHandler(cfg, configFilePath, authManager)
238239
if optionState.localPassword != "" {
@@ -716,6 +717,15 @@ func (s *Server) UpdateClients(cfg *config.Config) {
716717
}
717718
}
718719

720+
if oldCfg == nil || oldCfg.DisableCooling != cfg.DisableCooling {
721+
auth.SetQuotaCooldownDisabled(cfg.DisableCooling)
722+
if oldCfg != nil {
723+
log.Debugf("disable_cooling updated from %t to %t", oldCfg.DisableCooling, cfg.DisableCooling)
724+
} else {
725+
log.Debugf("disable_cooling toggled to %t", cfg.DisableCooling)
726+
}
727+
}
728+
719729
// Update log level dynamically when debug flag changes
720730
if oldCfg == nil || oldCfg.Debug != cfg.Debug {
721731
util.SetLogLevel(cfg)

internal/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ type Config struct {
3434
// UsageStatisticsEnabled toggles in-memory usage aggregation; when false, usage data is discarded.
3535
UsageStatisticsEnabled bool `yaml:"usage-statistics-enabled" json:"usage-statistics-enabled"`
3636

37+
// DisableCooling disables quota cooldown scheduling when true.
38+
DisableCooling bool `yaml:"disable-cooling" json:"disable-cooling"`
39+
3740
// QuotaExceeded defines the behavior when a quota is exceeded.
3841
QuotaExceeded QuotaExceeded `yaml:"quota-exceeded" json:"quota-exceeded"`
3942

@@ -183,6 +186,7 @@ func LoadConfigOptional(configFile string, optional bool) (*Config, error) {
183186
// Set defaults before unmarshal so that absent keys keep defaults.
184187
cfg.LoggingToFile = false
185188
cfg.UsageStatisticsEnabled = false
189+
cfg.DisableCooling = false
186190
if err = yaml.Unmarshal(data, &cfg); err != nil {
187191
if optional {
188192
// In cloud deploy mode, if YAML parsing fails, return empty config instead of error.

internal/watcher/watcher.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,9 @@ func buildConfigChangeDetails(oldCfg, newCfg *config.Config) []string {
11921192
if oldCfg.UsageStatisticsEnabled != newCfg.UsageStatisticsEnabled {
11931193
changes = append(changes, fmt.Sprintf("usage-statistics-enabled: %t -> %t", oldCfg.UsageStatisticsEnabled, newCfg.UsageStatisticsEnabled))
11941194
}
1195+
if oldCfg.DisableCooling != newCfg.DisableCooling {
1196+
changes = append(changes, fmt.Sprintf("disable-cooling: %t -> %t", oldCfg.DisableCooling, newCfg.DisableCooling))
1197+
}
11951198
if oldCfg.RequestLog != newCfg.RequestLog {
11961199
changes = append(changes, fmt.Sprintf("request-log: %t -> %t", oldCfg.RequestLog, newCfg.RequestLog))
11971200
}

sdk/cliproxy/auth/manager.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strconv"
99
"strings"
1010
"sync"
11+
"sync/atomic"
1112
"time"
1213

1314
"github.com/google/uuid"
@@ -44,6 +45,13 @@ const (
4445
quotaBackoffMax = 30 * time.Minute
4546
)
4647

48+
var quotaCooldownDisabled atomic.Bool
49+
50+
// SetQuotaCooldownDisabled toggles quota cooldown scheduling globally.
51+
func SetQuotaCooldownDisabled(disable bool) {
52+
quotaCooldownDisabled.Store(disable)
53+
}
54+
4755
// Result captures execution outcome used to adjust auth state.
4856
type Result struct {
4957
// AuthID references the auth that produced this result.
@@ -535,7 +543,10 @@ func (m *Manager) MarkResult(ctx context.Context, result Result) {
535543
shouldSuspendModel = true
536544
case 429:
537545
cooldown, nextLevel := nextQuotaCooldown(state.Quota.BackoffLevel)
538-
next := now.Add(cooldown)
546+
var next time.Time
547+
if cooldown > 0 {
548+
next = now.Add(cooldown)
549+
}
539550
state.NextRetryAfter = next
540551
state.Quota = QuotaState{
541552
Exceeded: true,
@@ -750,9 +761,13 @@ func applyAuthFailureState(auth *Auth, resultErr *Error, now time.Time) {
750761
auth.Quota.Exceeded = true
751762
auth.Quota.Reason = "quota"
752763
cooldown, nextLevel := nextQuotaCooldown(auth.Quota.BackoffLevel)
753-
auth.Quota.NextRecoverAt = now.Add(cooldown)
764+
var next time.Time
765+
if cooldown > 0 {
766+
next = now.Add(cooldown)
767+
}
768+
auth.Quota.NextRecoverAt = next
754769
auth.Quota.BackoffLevel = nextLevel
755-
auth.NextRetryAfter = auth.Quota.NextRecoverAt
770+
auth.NextRetryAfter = next
756771
case 408, 500, 502, 503, 504:
757772
auth.StatusMessage = "transient upstream error"
758773
auth.NextRetryAfter = now.Add(1 * time.Minute)
@@ -768,6 +783,9 @@ func nextQuotaCooldown(prevLevel int) (time.Duration, int) {
768783
if prevLevel < 0 {
769784
prevLevel = 0
770785
}
786+
if quotaCooldownDisabled.Load() {
787+
return 0, prevLevel
788+
}
771789
cooldown := quotaBackoffBase * time.Duration(1<<prevLevel)
772790
if cooldown < quotaBackoffBase {
773791
cooldown = quotaBackoffBase

0 commit comments

Comments
 (0)