MarcGiffing / bucket4j-spring-boot-starter

Spring Boot Starter for Bucket4j
Apache License 2.0
298 stars 63 forks source link

Bucket4jStartupCheckConfiguration crashs when using Spring-Boot @SessionScope #283

Closed gallusenrico closed 5 months ago

gallusenrico commented 5 months ago

I wanted to check out this really promising looking framework, but unfortunately i stumbled over an issue. I added the following configuration to my application.yaml:

bucket4j:
  enabled: true
  cache-to-use: redis-redisson
  filter-config-caching-enabled: true
  filter-config-cache-name: filterConfigCache
  filters:
    - cache-name: buckets
      filter-method: WEBFLUX
      filter-order: -10
      id: login
      url: /login
      rate-limits:
        - bandwidths:
          - capacity: 5
            time: 1
            unit: minutes

And also needed to add a configuration class and specify some beans in order to make the caching checks pass:

@Configuration
public class RateLimitConfig {
  @Bean
    public CommandAsyncExecutor commandAsyncExecutor(RedissonClient redissonClient) {
        return ((Redisson) redissonClient).getCommandExecutor();
    }
  @Bean
    public RedissonCacheResolver redissonCacheResolver(CommandAsyncExecutor commandAsyncExecutor) {
        return new RedissonCacheResolver(commandAsyncExecutor);
    }
}

When i started my application, it crashed during the Bucket4jStartupCheckConfiguration.getRateLimitingAnnotatedClasses with the following exception:

org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.sessionDataHolder': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:373) ~[spring-beans-6.1.1.jar:6.1.1]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.1.1.jar:6.1.1]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) ~[spring-context-6.1.1.jar:6.1.1]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[?:?]
    at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) ~[?:?]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[?:?]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[?:?]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575) ~[?:?]
    at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260) ~[?:?]
    at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616) ~[?:?]
    at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622) ~[?:?]
    at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627) ~[?:?]
    at com.giffing.bucket4j.spring.boot.starter.Bucket4jStartupCheckConfiguration.getRateLimitingAnnotatedClasses(Bucket4jStartupCheckConfiguration.java:202) ~[bucket4j-spring-boot-starter-0.12.5.jar:0.12.5]
    at com.giffing.bucket4j.spring.boot.starter.Bucket4jStartupCheckConfiguration.assertValidAnnotationConfiguration(Bucket4jStartupCheckConfiguration.java:76) ~[bucket4j-spring-boot-starter-0.12.5.jar:0.12.5]
    at com.giffing.bucket4j.spring.boot.starter.Bucket4jStartupCheckConfiguration.applicationReady(Bucket4jStartupCheckConfiguration.java:66) ~[bucket4j-spring-boot-starter-0.12.5.jar:0.12.5]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]

The sessionDataHolder-component that is the reason for the BeanCreationException uses a scope: @SessionScope.

If i remove the @SessionScope definition from the Component, the application boots up without any issues and successfully logs the registration of the filter specified in the application.yaml: INFO 36911 --- [ main] w.Bucket4JAutoConfigurationWebfluxFilter : create-webflux-filter;1;buckets;/login

Adding the @IgnoreRateLimiting annotation to the SessionScope class did not prevent the crash.

I wanted to write a test for it, but to be honest gave up on trying to make the tests run on my local system. Is there something i can do on my side to prevent this? Please let me know if you need any additional information!

MarcGiffing commented 5 months ago

Thanks for taking the time to fill the issue. For the method rate limit check I've tried to retrieve all beans to get the class. This obviously doesn't work for session scoped beans. I've changed the code get only the class instead of fetching the bean. I've created a 0.12.6-RC1 release. Can you please give it a try? This version should be available in a couple of hours.

MarcGiffing commented 5 months ago

I'm sorry. I got a timeout while releasing to nexus. I'll try it later again.

MarcGiffing commented 5 months ago

OK, 0.12.6-RC1 should be available soon

gallusenrico commented 5 months ago

Incredible response time! Fix works like a charm for me. Thank you so much