Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support redis-sentinel:// URLs when configuring a Redis client #21920

Closed
conanca opened this issue Jun 15, 2020 · 13 comments
Closed

Support redis-sentinel:// URLs when configuring a Redis client #21920

conanca opened this issue Jun 15, 2020 · 13 comments
Labels
status: superseded An issue that has been superseded by another

Comments

@conanca
Copy link

conanca commented Jun 15, 2020

When "spring.redis.url" set with

redis-sentinel :// [[username :] password@] host1[: port1] [, host2[: port2]] [, hostN[: portN]] [/ database][?[timeout=timeout[d|h|m|s|ms|us|ns]] [&sentinelMasterId=sentinelMasterId] [&database=database]]

(refer to redisuri.uri-syntax )

got an error with:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController': Unsatisfied dependency expressed through field 'redisTemplate'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisTemplate' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.class]: Unsatisfied dependency expressed through method 'redisTemplate' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Host must not be emptyorg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController': Unsatisfied dependency expressed through field 'redisTemplate'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisTemplate' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.class]: Unsatisfied dependency expressed through method 'redisTemplate' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Host must not be empty at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:895) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:109) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisTemplate' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.class]: Unsatisfied dependency expressed through method 'redisTemplate' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Host must not be empty at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:539) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1306) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] ... 28 common frames omittedCaused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Host must not be empty at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1306) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] ... 41 common frames omittedCaused by: java.lang.IllegalArgumentException: Host must not be empty at io.lettuce.core.internal.LettuceAssert.notEmpty(LettuceAssert.java:46) ~[lettuce-core-5.3.0.RELEASE.jar!/:5.3.0.RELEASE] at io.lettuce.core.RedisURI$Builder.redis(RedisURI.java:1044) ~[lettuce-core-5.3.0.RELEASE.jar!/:5.3.0.RELEASE] at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createRedisURIAndApplySettings(LettuceConnectionFactory.java:1132) ~[spring-data-redis-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createClient(LettuceConnectionFactory.java:1075) ~[spring-data-redis-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.afterPropertiesSet(LettuceConnectionFactory.java:279) ~[spring-data-redis-2.3.0.RELEASE.jar!/:2.3.0.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.2.6.RELEASE.jar!/:5.2.6.RELEASE] ... 52 common frames omitted

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 15, 2020
@wilkinsona
Copy link
Member

redis-sentinel:// URIs are specific to Lettuce while the spring.redis.url property is intended to work with both Lettuce and Jedis. If you want to configure sentinel support you should use the spring.redis.sentinel.* properties to do so.

@wilkinsona
Copy link
Member

We could consider supporting redis-sentinel:// URLs, perhaps via a Lettuce-specific spring.redis.lettuce.url property, but I think it may quite quickly become confusing with spring.redis.url and spring.redis.sentinel.* properties also being available.

@wilkinsona wilkinsona added the for: team-attention An issue we'd like other members of the team to review label Jun 15, 2020
@wilkinsona wilkinsona changed the title "spring.redis.url" does not suport Redis Sentinel Scheme Support redis-sentinel:// URLs when configuring a Redis client Jun 15, 2020
@wilkinsona wilkinsona added the type: enhancement A general enhancement label Jun 15, 2020
@mp911de
Copy link
Member

mp911de commented Jun 15, 2020

Sentinel can be configured for Jedis, too. In any case, Spring Boot would have to parse the URL and provide configuration values through the Redis sentinel configuration object instead of the Redis standalone configuration object.

Sentinel URL's may contain multiple hostnames which add to URL parsing complexity. It doesn't make sense to provide a Lettuce-specific option since the URL (spring.redis.url) isn't passed to any of the two Redis clients directly.

@wilkinsona
Copy link
Member

Thanks, Mark. While I knew that Sentinel can be configured for Jedis (hence the general spring.redis.sentinel.* properties), my understanding was that redis-sentinel:// URIs were a Lettuce-specific construct. Is that not the case?

@mp911de
Copy link
Member

mp911de commented Jun 15, 2020

redis-sentinel is somewhat Lettuce-specific. There are other libraries (https://www.rubydoc.info/gems/redis-sentinel, https://github.com/exponea/redis-sentinel-url) that follow a similar approach.

As per IANA, only the redis scheme is standardized.

@wilkinsona
Copy link
Member

We've opened #21999 to make the failure easier to diagnose. We'll leave this open for now while we consider what, if anything, to do.

@wilkinsona wilkinsona removed the for: team-attention An issue we'd like other members of the team to review label Jun 17, 2020
@snicoll
Copy link
Member

snicoll commented Jul 7, 2021

Support for RedisURI is tracked by spring-projects/spring-data-redis#2116 and we can look at this once this is implemented.

@snicoll snicoll added status: blocked An issue that's blocked on an external project change and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 7, 2021
@snicoll snicoll added this to the 2.x milestone Jul 7, 2021
@onobc
Copy link
Contributor

onobc commented Jul 10, 2021

Is the intention to support redis-sentinel:// URI under spring.redis.url for both Lettuce and Jedis? If so, I am not sure how the RedisURI -> RedisConfiguration feature will help as it is a Lettuce-only construct and would still leave the Jedis case needing to parse the URI into a RedisSentinelConfiguration.

If however, the more advanced URIs (redis-sentinel, redis-socket) set on spring.redis.url would only be supported when the underlying impl was Lettuce then I can see that the RedisURI -> RedisConfiguration feature would be super helpful.

@snicoll
Copy link
Member

snicoll commented Jul 11, 2021

Is the intention to support redis-sentinel:// URI under spring.redis.url for both Lettuce and Jedis?

I am not sure but we can make it Lettuce specific for a start.

@onobc
Copy link
Contributor

onobc commented Jul 11, 2021

Sounds good. I'm working on a proposal for the convenience factory in spring- data-redis.

@onobc
Copy link
Contributor

onobc commented Jul 11, 2021

Up until now the url was considered to conform to the redis|rediss URI scheme and therefore we only pulled the following info from the uri:

host, port, user, pass, db-number, ssl (based on scheme=rediss)

The Lettuce uri may also include the timeout query param (a client config option) which is also available as a direct config prop. For example:

spring.redis.connect-timeout: 10s

spring.redis.url: redis://myserver?timeout=12s

Should we prefer the value in the uri when set? Or, should we enforce using one form or the other (url or individual properties)? The latter is the approach taken by MongoDB auto-config for instance.

@onobc
Copy link
Contributor

onobc commented Jul 13, 2021

Now that the changes to spring-data-redis have merged I will consume them in a proposal here w/in the next couple of days.

@scottfrederick
Copy link
Contributor

Closing in favor of gh-27373

@scottfrederick scottfrederick added status: superseded An issue that has been superseded by another and removed type: enhancement A general enhancement status: blocked An issue that's blocked on an external project change labels Nov 10, 2021
@scottfrederick scottfrederick removed this from the 2.x milestone Nov 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: superseded An issue that has been superseded by another
Projects
None yet
Development

No branches or pull requests

7 participants