redis/node-redis

Memory leak observed for this library

Closed this issue · 2 comments

Description

Dynatrace graph with redis:

Image

DynaTrace grpah without redis:

Image

RedisStore.service.ts
`import { RedisStore } from 'connect-redis'; // Correct import for connect-redis
import { createClient, RedisClientType } from 'redis';
import { AppConfigService } from './AppConfig.service';

export class redisStore {
static redisClient: RedisClientType | null = null;

// Load and initialize the Redis client
static async loadRedis() {
if (this.redisClient) {
return; // Avoid reinitializing if already connected
}

const config = AppConfigService.config;
const { redisConfig } = config;

// Create the Redis client
this.redisClient = createClient({
  socket: {
    host: redisConfig?.host,
    port: redisConfig?.port,
    tls: redisConfig?.tls,
  },
  password: redisConfig?.password,
});

// Handle Redis client errors
this.redisClient.on('error', (err: Error) => {
  console.error('Redis Client Error:', err);
});

try {
  // Wait for the Redis client to connect
  await this.redisClient.connect();
  console.log('Connected to Redis');
} catch (err) {
  console.error('Failed to connect to Redis:', err);
  throw err;
}

}

// Create and return a new Redis session store
static getNewStore() {
this.loadRedis();
if (!this.redisClient) {
throw new Error(
'Redis client is not initialized. Call loadRedis() first.'
);
}
if (!this.redisClient.isOpen) {
throw new Error('Redis client is not connected!');
}
return new RedisStore({
client: this.redisClient,
});
}
}
**Session.service.ts**import _ from 'lodash';

import { AppConfigService } from './AppConfig.service';
import session from 'express-session';
import { redisStore } from './RedisStore.service';
import { NeedToUpdateAny } from '../types';

const config = AppConfigService.config;
const { secure, httpOnly, sameSite } = config;

export class SessionService {
static expressSession = session;
static readonly store: any = redisStore.getNewStore();
static isCallFromMicroApp = (url: string, checkArr?: string[]) => {
const originalUrl = /${url .replace(config.baseHref, '') .replace('/?', '') .toLowerCase()};
const url_split = originalUrl.split('/');
const appName = '/' + url_split[1].toLowerCase();
const appIdx = _.findIndex(config.microappServices, { path: appName });
if (!checkArr) return appIdx === -1;
return checkArr.every((path) => path !== appName) && appIdx === -1;
};
static cookiePath = config.baseHref || '/';
static commonConfig = {
...config.decrypt,
name: 'local.cookie',
proxy: true,
saveUninitialized: false,
cookie: { secure, httpOnly, sameSite, path: SessionService.cookiePath },
};

static singleSession = () => {
return this.expressSession({ ...this.commonConfig, resave: true });
};

static multiSession = () => {
const store = this.store;
return this.expressSession({
...this.commonConfig,
resave: false,
store,
});
};

static sessionSetup = (app: NeedToUpdateAny) => {
const config = AppConfigService.config;
if (config.redisConfig) {
app.use(SessionService.multiSession());
} else {
app.use(SessionService.singleSession());
}
};
}
`

Node.js Version

20

Redis Server Version

No response

Node Redis Version

4.7.0

Platform

Windows

Logs

No logs just see spike in the attached graph above with and without Dynatrace

@sairaj-baker

Thank you for reporting this potential memory leak. Since you're using connect-redis along with other libraries,
we'll need to first determine if the memory leak is specifically in node-redis itself,
rather than in the session handling or other middleware.

Could you create a minimal reproduction that:

  1. Uses only node-redis (without express-session, connect-redis, or other middleware)
  2. Demonstrates the same memory growth pattern
  3. Includes heap snapshots captured using Node's built-in tools before and after the memory growth

Please feel free to reopen when you have additional input.