Springboot fail to start if Redis is down

Redis is optional in my application & this is one of the requirement that even if Redis is down, application MUST be able to start without any issue.
I was able to handle this with spring-data-redis 1.8.1 version but it's causing issue when I upgraded to 2.0.1.
I was able to catch exception thrown during LettuceConnectionFactory but now it's throwing exception & control is not returned to calling class.
Please let me know how can I make Redis bean instantiation optional so that application server starts without any issue even if Redis is down.

SpringRedisConfig.java

   @Configuration
    public class SpringRedisConfig{
        private static final Logger logger = LoggerFactory.getLogger(SpringRedisConfig.class);

        @Value("${redis.config.file.path}")
        private String redisConfigFilePath;

        @Value("${redis.timeout}")
        private long redisTimeOut;

        public @Bean RedisTemplate redisTemplate(){
            RedisTemplate<String, Object> redisTemplate = null;
            try {
                redisTemplate = new RedisTemplate<>();
                redisTemplate.setKeySerializer(new StringRedisSerializer());
                redisTemplate.setHashKeySerializer(new StringRedisSerializer());
                redisTemplate.setHashValueSerializer(new GenericToStringSerializer<>(Long.class));
                redisTemplate.setConnectionFactory(connectionFactory());
            }catch(Exception e){
                logger.error("Error getting Redis Template connection ",e);
            }
            return redisTemplate;
        }

        @Bean
        public LettuceConnectionFactory connectionFactory() {
            LettuceConnectionFactory connectionFactory = null;
            try {
                ClientOptions clientOptions = ClientOptions.builder()
                        .cancelCommandsOnReconnectFailure(true)
                        .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
                        .build();
                RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost",
                        6379);
                LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder().clientOptions(clientOptions).build();
                connectionFactory = new LettuceConnectionFactory(standaloneConfig, lettuceClientConfiguration);
            }catch(Exception e){
                logger.error("Error ",e);
            }
            return connectionFactory;
        }
    }

Console output:

main] o.s.boot.SpringApplication               : Application startup failed

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisCacheManagerController': Unsatisfied dependency expressed through field 'redisCacheManagerProvider'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisCacheManagerProvider': Unsatisfied dependency expressed through field 'redisTemplate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisTemplate' defined in class path resource [com/kohls/jsl/cache/provider/config/SpringRedisConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: RedisConnectionFactory is required
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
        at com.kohls.browse.Application.main(Application.java:35) [classes/:na]
    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisCacheManagerProvider': Unsatisfied dependency expressed through field 'redisTemplate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisTemplate' defined in class path resource [com/kohls/jsl/cache/provider/config/SpringRedisConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: RedisConnectionFactory is required
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        ... 19 common frames omitted
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisTemplate' defined in class path resource [com/kohls/jsl/cache/provider/config/SpringRedisConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: RedisConnectionFactory is required
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        ... 32 common frames omitted
    Caused by: java.lang.IllegalStateException: RedisConnectionFactory is required
        at org.springframework.util.Assert.state(Assert.java:70) ~[spring-core-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.data.redis.core.RedisAccessor.afterPropertiesSet(RedisAccessor.java:38) ~[spring-data-redis-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at org.springframework.data.redis.core.RedisTemplate.afterPropertiesSet(RedisTemplate.java:123) ~[spring-data-redis-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
        ... 42 common frames omitted
  • Heroku crash (seems to be Sidekiq / Redis )

    I have the following issue when booting app on Heroku :

    2018-02-20T23:55:19.456182+00:00 heroku[worker.1]: Starting process with command `bundle exec sidekiq -e production -C config/sidekiq.yml`
    2018-02-20T23:55:20.180974+00:00 heroku[worker.1]: State changed from starting to up
    2018-02-20T23:55:23.590432+00:00 app[worker.1]: 4 TID-78no8 INFO: Booting Sidekiq 4.2.10 with redis options {:url=>"redis://h:REDACTED@ec2-34-252-234-97.eu-west-1.compute
    .amazonaws.com:27639"}
    2018-02-20T23:55:24.455410+00:00 heroku[worker.1]: Process exited with status 1
    2018-02-20T23:55:24.466303+00:00 heroku[worker.1]: State changed from up to crashed
    2018-02-20T23:55:24.271262+00:00 app[worker.1]: I, [2018-02-20T23:55:24.271106 #4]  INFO -- : DB Connection Pool size for Sidekiq Server before disconnect is: 1
    2018-02-20T23:55:24.274465+00:00 app[worker.1]: could not connect to server: No such file or directory
    2018-02-20T23:55:24.274469+00:00 app[worker.1]:         Is the server running locally and accepting
    2018-02-20T23:55:24.274471+00:00 app[worker.1]:         connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
    

    Seems to be a problem with redis but can't figure out what's wrong.

    sidekiq.yml

    development:
      :concurrency: 5
    production:
      :concurrency: 20
    :queues:
      - default
      - mailers
    

    Procfile

    web: bundle exec puma -C config/puma.rb
    worker: bundle exec sidekiq -e production -C config/sidekiq.yml
    

    Config vars

    REDIS_URL   redis://h:pe........stuff.here..........9fa3@ec2-34-252-234-97.eu-west-1.compute.amazonaws.com:27639
    

    Redis.rb

    $redis = Redis.new(url: ENV["REDIS_URL"])
    
  • Using cache with spring boot and redis embeded

    I want to use spring boot with caching data retrieved from rest web service. I propose to use redis for caching data. Is it possible to use embeded redis with spring boot without installing a redis software? If yes with which version of spring boot and how to do it?

    Thanks for your responses.

  • How to make Spring boot with Redis Sentinel work with Docker

    I am trying to set up a Spring boot application with Redis Sentinel 3.2.11 using docker. However I am getting

    Caused by: org.redisson.client.RedisConnectionException: Can't connect to servers!

    Any help would be highly appreciated

    My docker compose configuration

    version: '3.1'
    services:
      master:
        image: redis:3
      slave:
        image: redis:3
        command: redis-server --slaveof redis-master 6379
        links:
         - master:redis-master
      sentinel:
         build: sentinel
         environment:
          - SENTINEL_DOWN_AFTER=5000
          - SENTINEL_FAILOVER=5000
          - MASTER_NAME=redis-cluster
         links:
          - master:redis-master
          - slave
         networks:
          - spring
    networks:
      spring:
        external: true
    

    Docker file

    FROM redis:3
    
    EXPOSE 26379
    ADD sentinel.conf /etc/redis/sentinel.conf
    RUN chown redis:redis /etc/redis/sentinel.conf
    ENV SENTINEL_QUORUM 2
    ENV SENTINEL_DOWN_AFTER 30000
    ENV SENTINEL_FAILOVER 180000
    COPY sentinel-entrypoint.sh /usr/local/bin/
    RUN chmod +x /usr/local/bin/sentinel-entrypoint.sh
    ENTRYPOINT ["sentinel-entrypoint.sh"]
    

    Docker volume command:

    docker network create -o "com.docker.network.bridge.host_binding_ipv4"="192.168.17.1" spring

    Spring configuration in application.properties:

    redis.cluster.name=redis-cluster
    redis.sentinel.nodes=192.168.17.1:26379
    redis.timeout=2000
    
  • How to specify length of id in Redis

    How I can specify the length constraint of 'ID' from 15-25 symbols in my spring boot rest application using Redis?

    @RedisHash("Foo")
    public class Foo implements Serializable {
    
      @Id
      private Long id;
    
      @Indexed
      private Status status;
    }
    

    UPDATE

    I have tried to change id type to String and set Size for symbols length limitations but it doesn't work(it seems Size annotation ignored) in the scope of Redis db usage:

    @RedisHash("Foo")
    public class Foo implements Serializable {
    
      @Id
      @Size(min = 15, max = 25)
      private String id;
    
      @Indexed
      private Status status;
    }
    

    I have also tried to use custom validator also and the same behaviour - seems like it`s ignored when Redis db is used:

    @Documented
    @Constraint(validatedBy = DigitsLimitValidator.class)
    @Target({ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DigitsLimit {
    
      String message() default "Digits length is too short or long";
    
      Class<?>[] groups() default {};
    
      Class<? extends Payload>[] payload() default {};
    
      int min() default 5;
    
      int max() default 15;
    
    }
    

    Validator:

    public class DigitsLimitValidator implements ConstraintValidator<DigitsLimit, BigInteger> {
    
      private int min;
      private int max;
    
        @Override
        public void initialize(DigitsLimit value) {
          min = value.min();
          max = value.max();
        }
    
        @Override
        public boolean isValid(BigInteger value, ConstraintValidatorContext cxt) {
          return value != null && BigIntegerMath.log10(value, RoundingMode.FLOOR) + 1 >= min && BigIntegerMath.log10(value, RoundingMode.FLOOR) + 1 <= max;
        }
    
      }
    

    Model:

    @RedisHash("Foo")
    public class Foo implements Serializable {
    
      @Id
      @DigitsLimit(min = 15, max = 25)
      private BigInteger id;
    
      @Indexed
      private Status status;
    }
    

    Under debugging mode, I cannot catch any breakpoints inside my validator.

    In both attempts I can save any length of digits. Limitations are ignored. Why it was ignored?

  • I am trying to implement multuget operation in Spring on Redis, it throws me an error

    I am trying to execute MultiGet function in Spring on Redis. It throws me an error. I have implemented Get function successfully but while implementing mulitiGet() it asks me for Collection as second parameter. I am not sure what to enter? Can someone please guide me here.

    Here is my code for multiGet()

    Method definition: 
    @Override
     public User findById_MultiGet(String id) {
        return (User)hashOperations.multiGet("USER", id);
     }
    
    Code In Controller : 
    @GetMapping("Map/MultiGet/{id}")
     public User allMultiGet(@PathVariable("id") final String id)    {                                // MultiGet function
        return userRepository.findById_MultiGet(id);
    }
    

    Error for above multiget function I am getting is multiget(Object, Collection) type not (String,String) type

    Below code for Get function is working.

     public User findById(String id) {
        return (User)hashOperations.get("USER", id);
    }
    
     Code In Controller for Get function : 
     @GetMapping("Map/Get/{id}")
     public User allGet(@PathVariable("id") final String id) {                                // Get function
        return userRepository.findById(id);
    }