1
votes

We have a nodeJS server with express on AWS Elastic Beanstalk and we are trying to connect it with the Elasticache(Redis clustered) from the NodeJS but getting this error Redis Client Connection Error ClusterAllFailedError: Failed to refresh slots cache.. The error seems very common as a lot of people are facing the same bug. In order to connect to ElastiCache, we are using an npm module named ioredis.

A lot of people recommend using the same VPC and security group for both ElastiCache and Elastic Beanstalk. We are already using the same VPC and on Elastic Beanstalk we are using two security groups one of them matches the security group of ElastiCache. For the default VPC, we have enabled All Traffic for the inbound and outbound rules, but still, we are facing the same bug.

In order to connect to ElastiCache from NodeJS server I am using the following code:

const Redis = require("ioredis");
exports.connect = () => {
  const client = new Redis.Cluster(
    ["xxxxx.xxxxx.clustercfg.use1.cache.amazonaws.com:6379"],
    {
      slotsRefreshTimeout: 10000,
      dnsLookup: (address, callback) => callback(null, address),
      redisOptions: {
        showFriendlyErrorStack: true,
        tls: {
          checkServerIdentity: (/*host, cert*/) => {
            // skip certificate hostname validation
            return undefined;
          },
        },
      },
    }
  );
  client.on("ready", () => {
    console.log("Redis Client Ready");
  });
  client.on("connect", () => {
    console.log("Redis Client Connected");
  });
  client.on("error", (error) => {
    console.log("Redis Client Connection Error", error);
  });
  client.on("reconnecting", () => {
    console.log("Redis Client Reconnecting");
  });
  client.on("end", () => {
    console.log("Redis Client Connection ended");
  });
  return client;
};

ElastiCache Configuration enter image description here

Default VPC Security Group with Inbound and Outbound rules enter image description here enter image description here

Elastic Beanstalk security group(Same as default) enter image description here

Error information from Elastic Beanstalk enter image description here

Versions:

Node.js running on 64bit Amazon Linux with platform version 4.15.1

NodeJS version: 12.18.3

ioredis version: 4.17.3

npm version: 6.14.6

express version: 4.17.1

UPDATE: I am able to access the ElastiCache from ElasticBeanstalk if I do ssh and use redis-cli, but unable to access it using ioredis on NodeJS which is running on ElasticBeanstalk.

2
If you ssh into the EB instance, and just use redis-cli to connect manually it also does not work? This check would help to verify if the connection issue is instance wide, or limited to only your application.Marcin
@Marcin I just checked and I am able to access the ElastiCache by doing ssh into the EB instance.Alqama Bin Sadiq
So at least now you know that Security Groups and other networking setup is fine. So the cause must have something to do with your application.Marcin
@Marcin Yes, I think something is wrong with ioredisAlqama Bin Sadiq

2 Answers

0
votes

I have a similar setup and eventually got it working, a few key points:

  • Elasticbeanstalk and Elasticache have to be in the same VPC
  • Elasticache's security group should have an inbound rule to allow traffic from Elasticbeanstalk

Here's a code to connect:

import { RedisPubSub } from 'graphql-redis-subscriptions';
import Redis from 'ioredis';
import config from '../../config/env';

const options = {
  // AWS host will look like this: somecache-dev-ro.k6sjdj.ng.0001.use1.cache.amazonaws.com
  host: config.redis.host || 'localhost',
  port: config.redis.port || 6379,
  retryStrategy: (times: number): number => {
    // reconnect after
    return Math.min(times * 50, 2000);
  },
};

export const pubsub = new RedisPubSub({
  publisher: new Redis(options),
  subscriber: new Redis(options),
});
0
votes

I was debugging a similar issue. To access redis, I had to add tls: {} to the ioredis options:

{
      host: process.env.REDIS_HOST,
      port: process.env.REDIS_PORT,
      password: process.env.REDIS_PASSWORD,
      tls: {}
}