spring-cloud / spring-cloud/spring-cloud-gateway

RedisRateLimiter: Support configuration in Fluent API

Open
#2,246 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement help wanted
Dominant language
Java
Stars
4.9k
Forks
3.5k
Avg merge
20h 57m
Merged PRs (30d)
8

Description

Is your feature request related to a problem? Please describe.
There seems to be no way to configure the RedisRateLimiter per route when using the fluent API. It is readily available if using application.yaml configuration via filter args.

Describe the solution you'd like
To be honest I'm not completely sure what the best solution is. The trick here is that the RedisRateLimiter is an implementation of the RateLimiter. The filter itself is implemented via RequestRateLimiterGatewayFilterFactory. The reason this is tricky because filter configurations are easy, but this would actually need to seed the configuration for the individual ratelimiter.

Perhaps the most ideal might be a mechanism that allows the filter args to be passed through like we see with metadata.

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
     return builder.routes()
             .route("hello", p -> p.path("/api/v1/hello/**")
                     .filters(s -> s.requestRateLimiter(c -> c
                           .setRateLimiter(myRedisRateLimiter)
                           .setKeyResolver(keyResolver)
                           .filterArgs(Map.of("redis-rate-limiter.replenishRate", 60)))
                      .uri("helloService")
             ).build();
 }

The redis-rate-limiter.replenishRate could probably be a constant much like CONNECT_TIMEOUT_ATTR or RESPONSE_TIMEOUT_ATTR.

Alternatives 1
Alternatively maybe it would make sense for the configuration to occur at the specific ratelimiter implementation. That would create a less than desirable gap between the route definition, but it would provide for a better interface.

@Bean
public RedisRateLimiter redisRateLimiter() {
     RedisRateLimiter redisRateLimiter = new RedisRateLimiter(0, 0, 0);
     redisRateLimiter.configure("myRouteId", c-> c.setReplenishRate(10));
     return redisRateLimiter;
 }

Alternatives 2

A combination of the two solutions above might look something like this:

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
     return builder.routes()
             .route("hello", p -> p.path("/api/v1/hello/**")
                     .filters(s -> s.requestRateLimiter(c -> c
                           .setRateLimiter(myRedisRateLimiter.configure("hello",  c-> c.setReplenishRate(10))
                           .setKeyResolver(keyResolver)
                           .filterArgs(Map.of("redis-rate-limiter.replenishRate", 60)))
                      .uri("helloService")
             ).build();
 }

Additional context
Our use case is that our routing configuration has outgrown using the application.yaml. We have several situations where routes are dynamically determined and having them hardcoded doesn't work well.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing RequestRateLimiterGatewayFilterFactory, RateLimiter, and RedisRateLimiter to understand where fluent route configuration could be passed to the individual limiter. Done would be a decided, tested design for per-route RedisRateLimiter settings through the fluent API, but the issue does not identify specific tests or settle the interface.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, redis, spring, spring-boot
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.