66 "strings"
77 "sync"
88 "time"
9+
10+ log "github.com/sirupsen/logrus"
911)
1012
1113const (
@@ -19,7 +21,7 @@ const (
1921 DefaultSuspendCooldown = 1 * time .Hour
2022)
2123
22- // TokenState Token 状态
24+ // TokenState tracks per-token request and cooldown state.
2325type TokenState struct {
2426 LastRequest time.Time
2527 RequestCount int
@@ -32,10 +34,11 @@ type TokenState struct {
3234 SuspendReason string
3335}
3436
35- // RateLimiter 频率限制器
37+ // RateLimiter throttles Kiro requests and tracks token health.
3638type RateLimiter struct {
3739 mu sync.RWMutex
3840 states map [string ]* TokenState
41+ enabled bool
3942 minTokenInterval time.Duration
4043 maxTokenInterval time.Duration
4144 dailyMaxRequests int
@@ -47,24 +50,19 @@ type RateLimiter struct {
4750 rng * rand.Rand
4851}
4952
50- // NewRateLimiter 创建默认配置的频率限制器
53+ // NewRateLimiter creates a rate limiter with default settings.
5154func NewRateLimiter () * RateLimiter {
52- return & RateLimiter {
53- states : make (map [string ]* TokenState ),
54- minTokenInterval : DefaultMinTokenInterval ,
55- maxTokenInterval : DefaultMaxTokenInterval ,
56- dailyMaxRequests : DefaultDailyMaxRequests ,
57- jitterPercent : DefaultJitterPercent ,
58- backoffBase : DefaultBackoffBase ,
59- backoffMax : DefaultBackoffMax ,
60- backoffMultiplier : DefaultBackoffMultiplier ,
61- suspendCooldown : DefaultSuspendCooldown ,
62- rng : rand .New (rand .NewSource (time .Now ().UnixNano ())),
55+ rl := & RateLimiter {
56+ states : make (map [string ]* TokenState ),
57+ rng : rand .New (rand .NewSource (time .Now ().UnixNano ())),
6358 }
59+ rl .resetConfigLocked ()
60+ return rl
6461}
6562
66- // RateLimiterConfig 频率限制器配置
63+ // RateLimiterConfig defines rate limiter settings.
6764type RateLimiterConfig struct {
65+ Enabled * bool
6866 MinTokenInterval time.Duration
6967 MaxTokenInterval time.Duration
7068 DailyMaxRequests int
@@ -75,9 +73,37 @@ type RateLimiterConfig struct {
7573 SuspendCooldown time.Duration
7674}
7775
78- // NewRateLimiterWithConfig 使用自定义配置创建频率限制器
76+ // NewRateLimiterWithConfig creates a rate limiter with custom settings.
7977func NewRateLimiterWithConfig (cfg RateLimiterConfig ) * RateLimiter {
8078 rl := NewRateLimiter ()
79+ rl .applyConfigLocked (cfg )
80+ return rl
81+ }
82+
83+ // ApplyConfig reapplies config defaults and then applies overrides.
84+ func (rl * RateLimiter ) ApplyConfig (cfg RateLimiterConfig ) {
85+ rl .mu .Lock ()
86+ defer rl .mu .Unlock ()
87+ rl .applyConfigLocked (cfg )
88+ }
89+
90+ func (rl * RateLimiter ) resetConfigLocked () {
91+ rl .enabled = false
92+ rl .minTokenInterval = DefaultMinTokenInterval
93+ rl .maxTokenInterval = DefaultMaxTokenInterval
94+ rl .dailyMaxRequests = DefaultDailyMaxRequests
95+ rl .jitterPercent = DefaultJitterPercent
96+ rl .backoffBase = DefaultBackoffBase
97+ rl .backoffMax = DefaultBackoffMax
98+ rl .backoffMultiplier = DefaultBackoffMultiplier
99+ rl .suspendCooldown = DefaultSuspendCooldown
100+ }
101+
102+ func (rl * RateLimiter ) applyConfigLocked (cfg RateLimiterConfig ) {
103+ rl .resetConfigLocked ()
104+ if cfg .Enabled != nil {
105+ rl .enabled = * cfg .Enabled
106+ }
81107 if cfg .MinTokenInterval > 0 {
82108 rl .minTokenInterval = cfg .MinTokenInterval
83109 }
@@ -102,10 +128,16 @@ func NewRateLimiterWithConfig(cfg RateLimiterConfig) *RateLimiter {
102128 if cfg .SuspendCooldown > 0 {
103129 rl .suspendCooldown = cfg .SuspendCooldown
104130 }
105- return rl
131+
132+ // Validate interval bounds: max must be > min to avoid rand.Int63n panic.
133+ if rl .maxTokenInterval <= rl .minTokenInterval {
134+ log .Warnf ("kiro: rate limiter max-token-interval (%v) <= min-token-interval (%v), clamping max to min+1s" ,
135+ rl .maxTokenInterval , rl .minTokenInterval )
136+ rl .maxTokenInterval = rl .minTokenInterval + time .Second
137+ }
106138}
107139
108- // getOrCreateState 获取或创建 Token 状态
140+ // getOrCreateState returns the existing token state or creates one.
109141func (rl * RateLimiter ) getOrCreateState (tokenKey string ) * TokenState {
110142 state , exists := rl .states [tokenKey ]
111143 if ! exists {
@@ -117,7 +149,7 @@ func (rl *RateLimiter) getOrCreateState(tokenKey string) *TokenState {
117149 return state
118150}
119151
120- // resetDailyIfNeeded 如果需要则重置每日计数
152+ // resetDailyIfNeeded resets the daily counter when the window rolls over.
121153func (rl * RateLimiter ) resetDailyIfNeeded (state * TokenState ) {
122154 now := time .Now ()
123155 if now .After (state .DailyResetTime ) {
@@ -126,22 +158,26 @@ func (rl *RateLimiter) resetDailyIfNeeded(state *TokenState) {
126158 }
127159}
128160
129- // calculateInterval 计算带抖动的随机间隔
161+ // calculateInterval returns a randomized interval with jitter applied.
130162func (rl * RateLimiter ) calculateInterval () time.Duration {
131163 baseInterval := rl .minTokenInterval + time .Duration (rl .rng .Int63n (int64 (rl .maxTokenInterval - rl .minTokenInterval )))
132164 jitter := time .Duration (float64 (baseInterval ) * rl .jitterPercent * (rl .rng .Float64 ()* 2 - 1 ))
133165 return baseInterval + jitter
134166}
135167
136- // WaitForToken 等待 Token 可用(带抖动的随机间隔)
168+ // WaitForToken blocks until the token is allowed to send another request.
137169func (rl * RateLimiter ) WaitForToken (tokenKey string ) {
170+ if ! rl .enabled {
171+ return
172+ }
173+
138174 rl .mu .Lock ()
139175 state := rl .getOrCreateState (tokenKey )
140176 rl .resetDailyIfNeeded (state )
141177
142178 now := time .Now ()
143179
144- // 检查是否在冷却期
180+ // Wait until the cooldown window ends.
145181 if now .Before (state .CooldownEnd ) {
146182 waitTime := state .CooldownEnd .Sub (now )
147183 rl .mu .Unlock ()
@@ -151,7 +187,7 @@ func (rl *RateLimiter) WaitForToken(tokenKey string) {
151187 now = time .Now ()
152188 }
153189
154- // 计算距离上次请求的间隔
190+ // Respect the randomized spacing since the last request.
155191 interval := rl .calculateInterval ()
156192 nextAllowedTime := state .LastRequest .Add (interval )
157193
@@ -169,8 +205,12 @@ func (rl *RateLimiter) WaitForToken(tokenKey string) {
169205 rl .mu .Unlock ()
170206}
171207
172- // MarkTokenFailed 标记 Token 失败
208+ // MarkTokenFailed records a failed request for a token.
173209func (rl * RateLimiter ) MarkTokenFailed (tokenKey string ) {
210+ if ! rl .enabled {
211+ return
212+ }
213+
174214 rl .mu .Lock ()
175215 defer rl .mu .Unlock ()
176216
@@ -179,8 +219,12 @@ func (rl *RateLimiter) MarkTokenFailed(tokenKey string) {
179219 state .CooldownEnd = time .Now ().Add (rl .calculateBackoff (state .FailCount ))
180220}
181221
182- // MarkTokenSuccess 标记 Token 成功
222+ // MarkTokenSuccess clears any failure state after a successful request.
183223func (rl * RateLimiter ) MarkTokenSuccess (tokenKey string ) {
224+ if ! rl .enabled {
225+ return
226+ }
227+
184228 rl .mu .Lock ()
185229 defer rl .mu .Unlock ()
186230
@@ -189,8 +233,12 @@ func (rl *RateLimiter) MarkTokenSuccess(tokenKey string) {
189233 state .CooldownEnd = time.Time {}
190234}
191235
192- // CheckAndMarkSuspended 检测暂停错误并标记
236+ // CheckAndMarkSuspended detects suspension-like errors and records them.
193237func (rl * RateLimiter ) CheckAndMarkSuspended (tokenKey string , errorMsg string ) bool {
238+ if ! rl .enabled {
239+ return false
240+ }
241+
194242 suspendKeywords := []string {
195243 "suspended" ,
196244 "banned" ,
@@ -219,8 +267,12 @@ func (rl *RateLimiter) CheckAndMarkSuspended(tokenKey string, errorMsg string) b
219267 return false
220268}
221269
222- // IsTokenAvailable 检查 Token 是否可用
270+ // IsTokenAvailable reports whether the token can currently be used.
223271func (rl * RateLimiter ) IsTokenAvailable (tokenKey string ) bool {
272+ if ! rl .enabled {
273+ return true
274+ }
275+
224276 rl .mu .RLock ()
225277 defer rl .mu .RUnlock ()
226278
@@ -231,20 +283,20 @@ func (rl *RateLimiter) IsTokenAvailable(tokenKey string) bool {
231283
232284 now := time .Now ()
233285
234- // 检查是否被暂停
286+ // Suspended tokens stay unavailable until their suspension window expires.
235287 if state .IsSuspended {
236288 if now .After (state .SuspendedAt .Add (rl .suspendCooldown )) {
237289 return true
238290 }
239291 return false
240292 }
241293
242- // 检查是否在冷却期
294+ // Cooldown blocks reuse after failures.
243295 if now .Before (state .CooldownEnd ) {
244296 return false
245297 }
246298
247- // 检查每日请求限制
299+ // Enforce the per-day cap after refreshing the rolling window.
248300 rl .mu .RUnlock ()
249301 rl .mu .Lock ()
250302 rl .resetDailyIfNeeded (state )
@@ -260,15 +312,15 @@ func (rl *RateLimiter) IsTokenAvailable(tokenKey string) bool {
260312 return true
261313}
262314
263- // calculateBackoff 计算指数退避时间
315+ // calculateBackoff returns the exponential backoff for a failure count.
264316func (rl * RateLimiter ) calculateBackoff (failCount int ) time.Duration {
265317 if failCount <= 0 {
266318 return 0
267319 }
268320
269321 backoff := float64 (rl .backoffBase ) * math .Pow (rl .backoffMultiplier , float64 (failCount - 1 ))
270322
271- // 添加抖动
323+ // Add jitter so clients do not retry in lockstep.
272324 jitter := backoff * rl .jitterPercent * (rl .rng .Float64 ()* 2 - 1 )
273325 backoff += jitter
274326
@@ -278,7 +330,7 @@ func (rl *RateLimiter) calculateBackoff(failCount int) time.Duration {
278330 return time .Duration (backoff )
279331}
280332
281- // GetTokenState 获取 Token 状态(只读)
333+ // GetTokenState returns a defensive copy of the token state.
282334func (rl * RateLimiter ) GetTokenState (tokenKey string ) * TokenState {
283335 rl .mu .RLock ()
284336 defer rl .mu .RUnlock ()
@@ -288,19 +340,19 @@ func (rl *RateLimiter) GetTokenState(tokenKey string) *TokenState {
288340 return nil
289341 }
290342
291- // 返回副本以防止外部修改
343+ // Return a copy so callers cannot mutate internal state.
292344 stateCopy := * state
293345 return & stateCopy
294346}
295347
296- // ClearTokenState 清除 Token 状态
348+ // ClearTokenState removes all tracked state for a token.
297349func (rl * RateLimiter ) ClearTokenState (tokenKey string ) {
298350 rl .mu .Lock ()
299351 defer rl .mu .Unlock ()
300352 delete (rl .states , tokenKey )
301353}
302354
303- // ResetSuspension 重置暂停状态
355+ // ResetSuspension clears a token's suspension and cooldown markers.
304356func (rl * RateLimiter ) ResetSuspension (tokenKey string ) {
305357 rl .mu .Lock ()
306358 defer rl .mu .Unlock ()
0 commit comments