RedisRateLimiter: Support configuration in Fluent API
#2,246 opened on May 13, 2021
Repository metrics
- Stars
- (4,284 stars)
- PR merge metrics
- (Avg merge 1d 21h) (18 merged PRs in 30d)
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.