2

Node version: v14.15.4 Nest-js version: 9.0.0

app.module.ts Here is the code. In the app module, I am registering Redis as a cache manager.

@Module({
  imports: [
    CacheModule.register({
      isGlobal: true,
      store: redisStore,
      url: process.env.REDIS_URL,
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

service.ts The cache data method is for storing data with a key. -> the problem is the set function doesn't save anything

And get Data for returning the data by key.

@Injectable()
export class SomeService {
      constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

      async cacheData(key: string, data): Promise<void> {
        await this.cacheManager.set(key, data);
      }

      async getData(key: string, data): Promise<any> {
        return this.cacheManager.get(key);
      }
}




It doesn't throw any error in runtime.

Nairi Abgaryan
  • 616
  • 5
  • 16

8 Answers8

2

i has met the same problem as you,the way to fix this is using the install cmd to change the version of cache-manager-redis-store to 2.0.0 like 'npm i cache-manager-redis-store@2.0.0'

when you finish this step, the use of redisStore can be found,then the database can be linked.

xin cheng
  • 21
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Albert Logic Einstein Nov 27 '22 at 15:07
1

The default expiration time of the cache is 5 seconds.

To disable expiration of the cache, set the ttl configuration property to 0:

await this.cacheManager.set('key', 'value', { ttl: 0 });
tinkle
  • 36
  • 1
1

I had the same problem.

It looks like NestJS v9 incompatible with version 5 of cache-manager. So you need to downgrade to v4 for now, until this issue is resolved: https://github.com/node-cache-manager/node-cache-manager/issues/210

Change your package.json to have this in the dependencies:

"cache-manager": "^4.0.0",` 

Another commenter also suggested lowering the redis cache version.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
1

Set the redis store as redisStore.redisStore (You will get an autocomplete)

CacheModule.register({
  isGlobal: true,
  store: redisStore.redisStore,
  url: process.env.REDIS_URL,
})
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Deepak
  • 11
  • 1
1

I would like to add to the response of @Hailgrim which worked for me but I added types validations or casting for typescript and for saving an array of objects. I hope it will be useful!

  • "cache-manager": "^5.2.1"
  • "cache-manager-redis-store": "^2.0.0"
  • "@nestjs/cache-manager": "^1.0.0",
  • "@types/cache-manager-redis-store": "^2.0.1",

redis.module.ts

    import { Module } from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-store';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { CacheModule } from '@nestjs/cache-manager';
import { RedisService } from './redis.service';

const redisModuleFactory = CacheModule.registerAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    ttl: configService.get('CACHE_TTL'),
    store: redisStore,
    host: configService.get('CACHE_HOST'),
    port: configService.get('CACHE_PORT'),
  }),
  inject: [ConfigService],
});

@Module({
  imports: [redisModuleFactory],
  controllers: [],
  providers: [RedisService],
  exports: [RedisService],
})
export class RedisModule {}

and redis.service.ts

import { CACHE_MANAGER } from '@nestjs/cache-manager';
import {
  Inject,
  Injectable,
  InternalServerErrorException,
  Logger,
} from '@nestjs/common';
import { throws } from 'assert';
import { Cache } from 'cache-manager';

@Injectable()
export class RedisService {
  private logger = new Logger(RedisService.name);
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  async set(key: string, value: unknown): Promise<void> {
    try {
      await this.cacheManager.set(`yourglobalkey::${key}`, value);
    } catch (error) {
      throw new InternalServerErrorException();
    }
  }

  async get<T>(key: string): Promise<T | undefined> {
    try {
      const jsonData: string | undefined = await this.cacheManager.get<string>(
        `yourglobalkey::${key}`,
      );
      return jsonData ? JSON.parse(jsonData!) : undefined;
    } catch (error) {
      throw new InternalServerErrorException();
    }
  }
}

you can call it from outside like... my case an array of objects.

 const countries: yourType[] | undefined = await this.redisService.get<
      yourType[]
    >('yourkey');
javimetal
  • 11
  • 3
0

I am not sure why your getData function returns Promise<void> have you tried returning Promise<any> or the data type you are expecting e.g. Promise<string>. You could also try adding await.

 async getData(key: string, data): Promise<any> {
    return await this.cacheManager.get(key);
 }

Are you sure that you are connecting to redis successfully ?. Have you tried adding password and tls (true/false) configuration ?

@Module({
  imports: [
    CacheModule.register({
      isGlobal: true,
      store: redisStore,
      url: process.env.REDIS_URL,
      password: process.env.REDIS_PASSWORD,
      tls: process.env.REDIS_TLS
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
mh377
  • 1,656
  • 5
  • 22
  • 41
  • Thank you for noticing the type was wrong. But it can't be the cause of the issue because there are no types in runtime! Also, when we "return" data without "await", it will await automatically. – Nairi Abgaryan Aug 03 '22 at 05:05
  • Redis has no password, so there is no need to add it, and it is connected; otherwise, the app cannot run. – Nairi Abgaryan Aug 03 '22 at 05:12
  • Have you tried setting a TTL on the set method ? this.cacheManager.set(key, data, { ttl: 300, }); – mh377 Aug 03 '22 at 07:59
  • also is your redisStore from `import * as redisStore from 'cache-manager-redis-store';` "cache-manager": "^3.6.0", "cache-manager-redis-store": "^2.0.0", – mh377 Aug 03 '22 at 08:02
0

My stack:

  • Node.js@v18.15.0
  • Nest.js@9.3.12
  • cache-manager@5.2.0
  • cache-manager-redis-yet@4.1.1
  • redis@4.6.5

redis.service.ts:

import {
  CACHE_MANAGER,
  Inject,
  Injectable,
  InternalServerErrorException,
} from '@nestjs/common';
import { Cache } from 'cache-manager';

@Injectable()
export class RedisService {
  constructor(
    @Inject(CACHE_MANAGER)
    private cacheManager: Cache,
  ) {}
  async set(key: string, value: unknown): Promise<void> {
    try {
      await this.cacheManager.set(key, value, 0);
    } catch (error) {
      throw new InternalServerErrorException();
    }
  }

  async get(key: string): Promise<unknown> {
    try {
      return await this.cacheManager.get(key);
    } catch (error) {
      throw new InternalServerErrorException();
    }
  }
}

redis.module.ts:

import { CacheModule, Module } from '@nestjs/common';
import type { RedisClientOptions } from 'redis';
import { redisStore } from 'cache-manager-redis-yet';

import {
  REDIS_HOST,
  REDIS_PORT,
} from 'libs/config';
import { RedisService } from './redis.service';

@Module({
  imports: [
    CacheModule.register<RedisClientOptions>({
      isGlobal: true,
      store: redisStore,
      url: `redis://${REDIS_HOST}:${REDIS_PORT}`,
    }),
  ],
  providers: [RedisService],
  exports: [RedisService],
})
export class RedisModule {}

This code works fine for me.

0

The following works for me

My stack:

  • "@nestjs/common": "^9.2.1"
  • "cache-manager": "^5.2.0"
  • "cache-manager-redis-store": "^2.0.0"

Registered globally in app.module.ts

import { Module, CacheModule} from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-store';
@Module({
  imports: [
    CacheModule.registerAsync({
      isGlobal: true,
      useFactory: () => ({
        store: redisStore,
        url: process.env.REDIS_URL,
      }),
    }),
  ]
})

Make sure not to register the CacheModule again in your feature module, or the global one will be overwritten and the app will still use the in-memory cache instead of the Redis instance.

Then you can use the cache manager in your service files.