'How to connect AWS Elasticache Redis cluster to Spring Boot app?

I have Spring Boot app which connects to Redis cluster, using Jedis Connection Factory:

RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setPassword(redisProperties.getPassword());
jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration);

and reading list of nodes from application.yml:

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    timeout: 300s
    cluster:
      nodes: 127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382

Now we want to switch to Elasticache since we are hosting our Redis cluster on AWS anyway. It would be done quite easily. If AmazonElastiCache lib could be used. Then we could just connect to Elasticache cluster with AWS credentials, pull available nodes put it in the list and pass it to Jedis instead hardcoding them in application.yml, like:

//get cache cluster nodes using AWS api
private List<String> getClusterNodes(){
    AmazonElastiCache client = AmazonElastiCacheClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
    DescribeCacheClustersRequest describeCacheClustersRequest = new DescribeCacheClustersRequest();
    describeCacheClustersRequest.setShowCacheNodeInfo(true);
    List<CacheCluster> cacheClusterList = client.describeCacheClusters(describeCacheClustersRequest).getCacheClusters();
    List<String> nodeList = new ArrayList<>();
    try {
        for (CacheCluster cacheCluster : cacheClusterList) {
            for(CacheNode cacheNode :cacheCluster.getCacheNodes()) {
                String nodeAddr = cacheNode.getEndpoint().getAddress() + ":" +cacheNode.getEndpoint().getPort();
                nodeList.add(nodeAddr);
            }
        }
    }
    catch(Exception e) {
        e.printStackTrace();
    }
    return nodeList;
}

But DevOps team said that they can't configure AWS access on all labs and they have reasons for it. Also instead of connecting to AWS and pulling all available clusters we need to connect to specific one by URL.

So I tried to pass Elasticache cluster url directly to Jedis as standalone and as a cluster in application.yml configuration. In both cases connection is established, but when App tries to write to Elasticache its gets MOVED exception:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.data.redis.ClusterRedirectException: Redirect: slot 1209 to 10.10.10.011:6379.; nested exception is redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 1209 10.10.10.102:6379

Which as I understand means that App tried to write to one of the nodes in Elasticache, but wasn't able to connect.

So the question would be is there a way to connect to Elasticache Redis cluster from Spring Boot app using only Elasticache cluster URL?

I know that it's doable if Elasticache Memecache is used. Also Jedis driver is not a hard requirement.

Thank you.



Solution 1:[1]

Inspired from Above Answer:, complete more detailed code

 List<String> nodes = Collections.singletonList("<cluster-host-name>:<port>");
 RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);
 
 ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder().closeStaleConnections(true)
 .enableAllAdaptiveRefreshTriggers().build();
 
 ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder().autoReconnect(true)
 .topologyRefreshOptions(topologyRefreshOptions).validateClusterNodeMembership(false)
 .build();
 //If you want to add tuning options
 LettuceClientConfiguration  lettuceClientConfiguration = LettuceClientConfiguration.builder().readFrom(ReadFrom.REPLICA_PREFERRED).clientOptions(clusterClientOptions).build();
 
 LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfiguration, lettuceClientConfiguration);
 lettuceConnectionFactory.afterPropertiesSet();//**this is REQUIRED**
 StringRedisTemplate redisTemplate = new StringRedisTemplate(lettuceConnectionFactory);

Solution 2:[2]

For this kind of situation, you need to send SMS from the backend. There are a lot of different services for this but what comes to my mind now is Twilio.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Robbo_UK
Solution 2 David Prusa