Bucket4j with Redisson , the number of tokens is always same in bucket

217 views Asked by At

I'm using these two dependency the code is also shared below , the issue is when I'm trying to run the application for the rate limit everytime I'm consuming the bucket its token is always the same. The expectation is suppose if the refill is set to 2mins and then if I'm consuming for the first time the left token should be 3 , then 2 then 1 and then 429 request.

<bucket4j.starter.version>0.9.1</bucket4j.starter.version><redisson.version>3.24.1</redisson.version>
<dependency>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>snakeyaml</artifactId>
            <groupId>org.yaml</groupId>
        </exclusion>
    </exclusions>
    <groupId>org.redisson</groupId>
    <version>${redisson.version}</version>
</dependency>
<dependency>
    <artifactId>bucket4j-spring-boot-starter</artifactId>
    <groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
    <version>${bucket4j.starter.version}</version>
</dependency>
@Configuration
public class RedisConfig {

    @Autowired
    private VcapUtils vcapUtils;

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress(vcapUtils.getRedisURI());
        config.setCodec(new SerializationCodec());
        return Redisson.create(config);
    }

    @Bean
    public Config config() {
        Config config = new Config();
        config.useSingleServer().setAddress(vcapUtils.getRedisURI());
        config.setCodec(new SerializationCodec());
        return config;
    }

    @Bean(name = "springCM")
    public CacheManager cacheManager(Config config) {
        CacheManager cacheManager = Caching.getCachingProvider().getCacheManager();
        cacheManager.createCache("rateLimit", RedissonConfiguration.fromConfig(config));
        return cacheManager;
    }

    @Bean
    public ProxyManager<String> proxyManager(CacheManager cacheManager) {
        return new JCacheProxyManager<>(cacheManager.getCache("rateLimit"));
    }
}

@Component
public class RateLimitConfig extends OncePerRequestFilter {

    private static final Set<String> URL_TO_BE_IGNORED = Sets.newHashSet(
        "/dvh/api/v1/vehicle/$count",
        "/dvh/api/v1/vehicle/search",
        "/dvh/api/v1/vehicle/attributes"
    );

    @Autowired
    private BucketConfig bucketConfig;

    @Autowired
    private ProxyManager<String> proxyManager;

    private VcapApplication vcapApplication;

    @Autowired
    public RateLimitConfig() {
        this.vcapApplication = VcapApplication.fromEnvironment();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
        FilterChain filterChain) throws ServletException, IOException {

        Boolean requestURL = URL_TO_BE_IGNORED.contains(request.getRequestURI());

        if (Boolean.TRUE.equals(requestURL)) {
            filterChain.doFilter(request, response);
            return;
        }

        Bucket bucket = bucketConfig.resolveBucket(SpringSecurityContext.getToken().getZoneId());
        ConsumptionProbe probe = bucket.tryConsumeAndReturnRemaining(1);

        if (probe.isConsumed()) {
            response.setHeader("X-Rate-Limit-Remaining",
                String.valueOf(probe.getRemainingTokens()));
            filterChain.doFilter(request, response);
        } else {
            response.setHeader("X-Rate-Limit-Retry-After-Seconds",
                String.valueOf(probe.getNanosToWaitForRefill() / 1_000_000_000));
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        }
    }
}

@Component
public class BucketConfig {

    private static final Logger logger = LoggerFactory.getLogger(BucketConfig.class);

    private static final Integer DEFAULT_API_RATE_LIMIT = 4;

    private static final Integer REFILL_INTERVAL_IN_SECONDS = 2;

    @Autowired
    private ProxyManager<String> proxyManager;

    public Bucket resolveBucket(String tenantID) {
        Supplier<BucketConfiguration> configSupplier = getConfigSupplierForTenant(tenantID);
        return proxyManager.builder().build(tenantID, configSupplier);
    }

    private Supplier<BucketConfiguration> getConfigSupplierForTenant(String tenantID) {
        Bandwidth limit = Bandwidth.simple(DEFAULT_API_RATE_LIMIT,
            Duration.ofMinutes(REFILL_INTERVAL_IN_SECONDS)).withId(tenantID);
        return () -> (BucketConfiguration.builder()
            .addLimit(limit)
            .build());
    }
}

please Note I tried almost everything to make this code work but it didn't , the url and everything is fine and I don't want to go other way like hazelcast or jedis

0

There are 0 answers