1

Upon trying to connect to a remote Redis instance hosted in AWS from a SpringBoot application, RedisConnectionFactory keeps attempting to connect to localhost:6379 even although the target host has been specified in different ways. This problem occurs both from my development laptop and our development environment. I am able to connect to the target host from Redis InSight as well as from another microservice and, oddly, that microservice has an identical configuration to the one that is failing.

This is my default configuration class:

@Configuration
public class RedisCacheConfig {

     @Value("${spring.data.redis.host}")
     private String host;

     @Value("${spring.data.redis.port}")
     private String port;

     @Value("${spring.caching.ttl.findAllBillingByEstadoTTL}")
     private Integer findAllBillingByEstadoTTLValue;

     @Bean
     public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(host);
        config.setPort(Integer.parseInt(port));

        LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
                .useSsl()
                .and()
                .commandTimeout(Duration.ofMillis(6000))
                .build();

        return new LettuceConnectionFactory(config, lettuceClientConfiguration);
     }

    @Bean
    GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
    return RedisCacheConfiguration.defaultCacheConfig()
            .disableCachingNullValues()
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer()));
    }

    @Bean
    RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
        return (builder) -> builder
                .withCacheConfiguration("findAllBillingByEstado",
                        RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(findAllBillingByEstadoTTLValue)));
    }
}

As you can see, I'm not using an argument-less constructor for the LettuceConnectionFactory, which is a problem shown in several similar questions such as this one. I wasn't using the .useSsl() method before, but I gave it a try based on this question to no avail. Finally, based on this GitHub issue I also removed the ReactiveRedisConnectionFactory bean in order to rely on Spring's autoconfiguration, but it still insists on connecting to localhost.

What else could cause this problem?

LeperAffinity666
  • 364
  • 4
  • 14

1 Answers1

0

You haven't provided enough information to adequately identify the root cause of your issue in this case, such as the version of the Spring bits you are using?

You mention Spring "auto-configuration", so I am assuming you are actually using Spring Boot.

In your title, you mention you are configuring your Spring [Boot] application using an application.yml file, but you have not shared the configuration.

NOTE: The use of an application.yaml also suggests the use of Spring Boot.

NOTE: The YAML configuration file extension is actually .yaml, NOT .yml.

Your issue may possibly be an error in the format of your application.yaml file (it has to be precise; see docs):

spring:
  data:
    redis:
      host: "some-host"
      port: 6379
      database: 0
      username: "user"
      password: "secret"

Or, maybe you have not properly declared the necessary Spring Boot, Redis-specific application properties in YAML?

Are you possibly using Spring profiles for different environments with additional configuration files by environment?

I also think you should check the extension of your application YAML configuration file since (if) you are using .yml, Spring Boot docs clearly call out .yaml. Specifically, review this doc.

Reviewing the available properties in Spring Boot for Redis (and specifically, Spring Data Redis), both spring.data.redis.host and spring.data.redis.port are valid properties.

You can actually simplify your injection of the port property using:

@Value("${spring.data.redis.port}")
private int port;

Spring will handle the value conversion (from String to a primitive int, or alternatively, a wrapper Integer object, which can handle null assignments) on assignment here.

Although, your use of property injections for these Redis properties should be unnecessary...

I am actually curious why you would even declare a [Reactive]RedisConnectionFactory bean in the first place?

Spring Boot auto-configuration will automatically configure a Redis connection when both Spring Data Redis and a Redis (client) driver are on your application classpath, such as by declaring the spring-boot-starter-data-redis dependency.

NOTE: The Spring Boot spring-boot-starter-data-redis dependency declares the Lettuce driver on your application classpath, by default. See here. Also see the documentation.

NOTE: Also note, if your application needs to be "Reactive", then you should probably declare the spring-boot-starter-data-redis-reactive dependency instead.

See the Spring Boot, RedisAutoConfiguration class from here to here.

By declaring a RedisConnectionFactory bean in your application configuration explicitly, you have effectively "overridden" Spring Boot's auto-configuration.

If you need to customize the configuration like this, then you can simply do so either in properties (using either Java Properties or YAML configuration), or using an appropriate Customizer.

So, your Spring @Configuration class could have simply been:

@Configuration
class RedisCacheConfig { 

  @Bean
  LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer() {

    return builder -> builder
      .useSsl()
      .and()
      .commandTimeout(Duration.ofMillis(6000));
  }

  // your other (cache) bean configuration here

}

This should trigger this code (line) in Spring Boot auto-configuration, particularly if you have not declared Sentinel or Cluster configuration (as seen here), thereby defaulting to "standalone".

Of course, you can always inspect (debug or log) the configuration of your Spring Boot (Redis) application by injecting the properties as you have done, or alternatively (recommended), injecting either the RedisProperties (here) or a RedisConnectionDetails object (here), specifically, which are declared and auto-configured by Spring Boot. You can see Spring Boot injects those objects into the constructor of the Spring Boot's RedisConnectionConfiguration class here. Then, you can access the Redis property configuration in an OO manner from 1 of those objects.

Also, pay particular attention to the "standalone" configuration (here) provided by Spring Boot.

John Blum
  • 7,381
  • 1
  • 20
  • 30