redis / redis/node-redis

Memory leak : ReddisClient () slowly increases the memory and finally crashes the server

Open
#2,204 8 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug stale
Dominant language
TypeScript
Stars
17.6k
Forks
2k
Avg merge
2d 3h
Merged PRs (30d)
40

Description

I'm using "redis": "^3.1.2". My containers are restarting/ crashing in prod due to a memory leak.
The traffic is very very less around 650 in 24 hours. Following are my observations:

  1. For the first few 100 requests the memory would be around 200/300 MB and it would stay the same even after an hour without traffic.GC couldn't clear the memory. so after subsequent few 100 requests, the memory increases and it crashes my container (my container setting in prod is 1GB.)

  2. I have used google chrome inspect to understand which object or function is causing this. And it turned out to be Redis client is holding very less memory at the beginning and after leaving it for a while the memory it holds keeps on increasing.(I have taken the snapshots of heap over time and compared the difference).

  3. I'm actually connecting to reddis for every request and closing the connection using the connection.quit(). But another observation I found inside the Redis module there is a stream that continuously runs and does something recursively. upon debugging I found the connection is still alive. So I changed the method to end() instead of quit and it still produces the stream. and the connection is still alive. At this point, I'm literally stuck. please help me with the following question 👍

    I) is it advised to connect to Redis and close for every request.
    2) Is it normal to have a memory leak when using Redis module
    3) irrespective of quit or end the stream doesn't stop in the background (for example keep a debug in individual.commands.js -> info_callback method and monitor the connection status.)

Code

`connect(config) {
const connectionRetryTime = 1000 * 60 * 60;
const clientOptions = {
host: config.endpoint.host,
port: config.endpoint.port,
socket_keepalive: true,
password: config.redisAuth,
tls: true,
retry_strategy: (options) => {
if (options.error && options.error.code === 'ECONNREFUSED') {
return new Error('The server refused the connection');
}
if (options.total_retry_time > connectionRetryTime) {
return new Error('Retry time exhausted');
}
if (options.attempt > 2) {
return undefined;
}

    return Math.min(options.attempt * 100, 3000);
  },
};

return new Promise(((resolve, reject) => {
  try {
    this.cacheProvider = redis.createClient(clientOptions);
    this.cacheProvider.on('error', () => {
      // eslint-disable-next-line no-console
      console.error('Error Connecting to Redis error');
    });

    // Get promisified version of RedisClient functions
    this.getAsync = promisify(this.cacheProvider.get).bind(this.cacheProvider);
    this.setAsync = promisify(this.cacheProvider.set).bind(this.cacheProvider);
    this.setexAsync = promisify(this.cacheProvider.setex).bind(this.cacheProvider);
    this.keysAsync = promisify(this.cacheProvider.keys).bind(this.cacheProvider);
    this.pingAsync = promisify(this.cacheProvider.ping).bind(this.cacheProvider);
    this.quitAsync = promisify(this.cacheProvider.quit).bind(this.cacheProvider);

    return resolve(this.cacheProvider);
  } catch (error) {
    return reject(error);
  }
}));

}

init(config) {
return this.connect(config);
}

healthCheck() {
return this.pingAsync();
}

async release() {
return this.cacheProvider.quitAsync;
}
`

For each request I'm

init();
get();
release();

Environment:

  • **Node.js Version14:
  • Redis Server Version:
  • **Node Redis Version3.1.2:
  • **PlatformmacOS 12.4:

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the provided connect(), init(), healthCheck(), and release() lifecycle using Node.js 14 and redis 3.1.2, then reproduce the reported memory and connection behavior under repeated requests. Compare the effects of quit() and end() and verify whether release() actually closes the client; done means the retained stream or connection behavior and a reproducible cause are identified.

Written by the indexing model from the issue text.

Assessment

Tech stack
nodejs, redis
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.