Bug Report
Current Behavior
When starting a SpringBoot 4.1.0 application that has Redis autoconfigured, it crashes on startup with an exception originating from lettuce:
Stack trace
``[org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:977)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:621)
at org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:756)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1365)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354)
at com.vw.mbbc.cdpsync.Application.main(Application.java:23)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:106)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/cache/autoconfigure/RedisCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 4: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/data/redis/autoconfigure/LettuceConnectionConfiguration.class]: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1360)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1192)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:565)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309)
... 15 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/data/redis/autoconfigure/LettuceConnectionConfiguration.class]: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1360)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1192)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:565)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:1232)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1711)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1658)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:912)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
... 25 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:183)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:72)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:152)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
... 39 more
Caused by: java.lang.NoClassDefFoundError: jdk/net/ExtendedSocketOptions
at io.lettuce.core.resource.ExtendedKeepAliveSupport$ExtendedNioSocketOptions.(ExtendedKeepAliveSupport.java:110)
at io.lettuce.core.resource.ExtendedKeepAliveSupport.(ExtendedKeepAliveSupport.java:45)
at io.lettuce.core.SocketOptions$Builder.(SocketOptions.java:118)
at io.lettuce.core.SocketOptions$Builder.(SocketOptions.java:107)
at io.lettuce.core.SocketOptions.builder(SocketOptions.java:92)
at io.lettuce.core.SocketOptions.create(SocketOptions.java:101)
at io.lettuce.core.ClientOptions.(ClientOptions.java:79)
at org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration$LettuceClientConfigurationBuilder.(LettuceClientConfiguration.java:182)
at org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.builder(LettuceClientConfiguration.java:138)
at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.createBuilder(LettuceConnectionConfiguration.java:166)
at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.getLettuceClientConfiguration(LettuceConnectionConfiguration.java:149)
at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.createConnectionFactory(LettuceConnectionConfiguration.java:122)
at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.redisConnectionFactory(LettuceConnectionConfiguration.java:99)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:155)
... 42 more
Caused by: java.lang.ClassNotFoundException: jdk.net.ExtendedSocketOptions
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.loadClass(JarUrlClassLoader.java:107)
at org.springframework.boot.loader.launch.LaunchedClassLoader.loadClass(LaunchedClassLoader.java:91)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
... 58 more" ``
Input Code
No specific code, attempting to start a SpringBoot application with redis configured in will lead to this error under the conditions specified in "Environment".
Expected behavior/code
Fall back to plain SO_KEEPALIVE (was made default in 7.5.0) and continue running with reduced keepalive granularity. I.e. graceful degradation rather than full application crash. In other words: pre-7.5.0 behaviour.
Environment
- lettuce-core: 7.5.2.RELEASE (via spring-boot-starter-data-redis, Spring Boot 4.1.0)
- Previously working: lettuce-core 6.8.2.RELEASE (via Spring Boot 4.0.6), no crash
- JDK: 21, running as a custom jlink-built runtime image that does not include the
jdk.net module, inside a docker container. Unfortunately we don't control the process the creation of that image, otherwise adding jdk.net to the list of modules would've been the path of least resistance.
Possible Solution
Making keepalive behaviour configurable would do in a pinch, defensively guarding against non-availability of jdk.netExtendedSocketOptions would probably be the more sustainable (and elegant) solution. For the purposes of what I'm trying to achieve (being able to closely keep tracking springboot releases), either is fine.
Regression note
This did not occur with lettuce-core 6.8.2.RELEASE (Spring Boot 4.0.6), where extended keepalive was opt-in. It became a startup-blocking issue specifically because #3669 made the capability probe run unconditionally as part of a static default.
Bug Report
Current Behavior
When starting a SpringBoot 4.1.0 application that has Redis autoconfigured, it crashes on startup with an exception originating from lettuce:
Stack trace
``[org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:977) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:621) at org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:756) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445) at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1365) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) at com.vw.mbbc.cdpsync.Application.main(Application.java:23) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:106) at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/cache/autoconfigure/RedisCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 4: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/data/redis/autoconfigure/LettuceConnectionConfiguration.class]: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1360) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1192) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:565) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) ... 15 more Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/data/redis/autoconfigure/LettuceConnectionConfiguration.class]: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1360) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1192) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:565) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:1232) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1711) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1658) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:912) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ... 25 more Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception with message: jdk/net/ExtendedSocketOptions at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:183) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:72) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:152) at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ... 39 more Caused by: java.lang.NoClassDefFoundError: jdk/net/ExtendedSocketOptions at io.lettuce.core.resource.ExtendedKeepAliveSupport$ExtendedNioSocketOptions.(ExtendedKeepAliveSupport.java:110) at io.lettuce.core.resource.ExtendedKeepAliveSupport.(ExtendedKeepAliveSupport.java:45) at io.lettuce.core.SocketOptions$Builder.(SocketOptions.java:118) at io.lettuce.core.SocketOptions$Builder.(SocketOptions.java:107) at io.lettuce.core.SocketOptions.builder(SocketOptions.java:92) at io.lettuce.core.SocketOptions.create(SocketOptions.java:101) at io.lettuce.core.ClientOptions.(ClientOptions.java:79) at org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration$LettuceClientConfigurationBuilder.(LettuceClientConfiguration.java:182) at org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.builder(LettuceClientConfiguration.java:138) at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.createBuilder(LettuceConnectionConfiguration.java:166) at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.getLettuceClientConfiguration(LettuceConnectionConfiguration.java:149) at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.createConnectionFactory(LettuceConnectionConfiguration.java:122) at org.springframework.boot.data.redis.autoconfigure.LettuceConnectionConfiguration.redisConnectionFactory(LettuceConnectionConfiguration.java:99) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:155) ... 42 more Caused by: java.lang.ClassNotFoundException: jdk.net.ExtendedSocketOptions at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593) at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.loadClass(JarUrlClassLoader.java:107) at org.springframework.boot.loader.launch.LaunchedClassLoader.loadClass(LaunchedClassLoader.java:91) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) ... 58 more" ``Input Code
No specific code, attempting to start a SpringBoot application with redis configured in will lead to this error under the conditions specified in "Environment".
Expected behavior/code
Fall back to plain
SO_KEEPALIVE(was made default in 7.5.0) and continue running with reduced keepalive granularity. I.e. graceful degradation rather than full application crash. In other words: pre-7.5.0 behaviour.Environment
jdk.netmodule, inside a docker container. Unfortunately we don't control the process the creation of that image, otherwise adding jdk.net to the list of modules would've been the path of least resistance.Possible Solution
Making keepalive behaviour configurable would do in a pinch, defensively guarding against non-availability of jdk.netExtendedSocketOptions would probably be the more sustainable (and elegant) solution. For the purposes of what I'm trying to achieve (being able to closely keep tracking springboot releases), either is fine.
Regression note
This did not occur with lettuce-core 6.8.2.RELEASE (Spring Boot 4.0.6), where extended keepalive was opt-in. It became a startup-blocking issue specifically because #3669 made the capability probe run unconditionally as part of a static default.