HY-love-sleep opened a new pull request, #7166:
URL: https://github.com/apache/shenyu/pull/7166

   ### Motivation
   
   Fixes #6649. `recordTokensUsage` re-issued the expiration after every 
increment:
   
   ```java
   reactiveRedisTemplate.opsForValue()
           .increment(cacheKey, tokens)
           .flatMap(currentValue -> reactiveRedisTemplate.expire(cacheKey, 
Duration.ofSeconds(windowSeconds)))
           .subscribe();
   ```
   
   so as long as requests kept arriving within `windowSeconds` the counter 
never expired and the budget of the
   window was never reset: "N tokens per window" behaved as a monotonic 
lifetime cap, and sustained traffic
   stayed throttled until a quiet period.
   
   ### What changed
   
   The counter now gets its window when the key is created, and the expiration 
is never re-issued:
   
   ```java
   final ReactiveValueOperations valueOperations = 
reactiveRedisTemplate.opsForValue();
   valueOperations.setIfAbsent(cacheKey, 0L, Duration.ofSeconds(windowSeconds))
           .then(valueOperations.increment(cacheKey, tokens))
           .subscribe();
   ```
   
   `SET NX` with a TTL creates the counter and its window in the same atomic 
command, and `INCR` adds the usage
   of the current request. A key that already exists keeps the window it was 
created with, so the counter expires
   on schedule and the first request of the next window starts from zero again.
   
   I used `SET NX` + `INCR` rather than `INCR` + `EXPIRE NX` (the other option 
suggested in the issue) because the
   TTL is then attached by the command that creates the key: if the process 
dies between the two commands, the
   counter still carries a window instead of living forever.
   
   ### Testing
   
   ```
   ./mvnw -pl shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-token-limiter -am 
test
   ```
   
   `BUILD SUCCESS`, checkstyle clean, `AiTokenLimiterPluginTest` 8/8 including 
the new case: the counter is
   created with `setIfAbsent(key, 0, window)`, the usage is incremented on it, 
and `expire(...)` is **never**
   called any more.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to