nestjs / cache-manager Goto Github PK
View Code? Open in Web Editor NEWCache manager module for Nest framework (node.js) ๐
License: MIT License
Cache manager module for Nest framework (node.js) ๐
License: MIT License
When I have a method like this, I can't set the cache key using id:
Similarly, customize the CacheKey:
No response
If the "register" method options include a "useClass" property, the class will not be utilized to determine the cache manager's options.
I am not sure if this is an issue in this repository or in the @nestjs/core repository.
https://github.com/mmuenker/cache-options-are-not-resolved
During startup, the CacheModule.register function creates an instance of the CacheModuleOptionsLoader class, which is defined with useClass property.
2.2.1
10.3.2
18.18.2
$ yarn start
[Nest] 665160 - 02/08/2024, 2:50:23 PM LOG [NestFactory] Starting Nest application...
[Nest] 665160 - 02/08/2024, 2:50:23 PM LOG [InstanceLoader] CacheModule dependencies initialized +8ms
[Nest] 665160 - 02/08/2024, 2:50:23 PM LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 665160 - 02/08/2024, 2:50:23 PM LOG [RoutesResolver] AppController {/}: +4ms
[Nest] 665160 - 02/08/2024, 2:50:23 PM LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 665160 - 02/08/2024, 2:50:23 PM LOG [NestApplication] Nest application successfully started +1ms
role.services.ts like this:
...
@Inject(forwardRef(() => MenuService)) private readonly menuService: WrapperType,
.....
base.service.ts :
.....
async setCache(param: { value: any; key?: string; ttl?: Milliseconds }) {
const { key = this.cacheKey, value, ttl } = param;
return await this.cacheManager.set(key, value, ttl);
}
......
=============
unhandledRejection: TypeError: Cannot read properties of undefined (reading 'set')
at RoleService.setCache (C:\work\dasplus\src\common\services\base.service.ts:45:40)
at C:\work\dasplus\src\common\services\base.service.ts:38:24
at processTicksAndRejections (node:internal/process/task_queues:95:5)
No response
can use
^5.4.0
^10.3.3
v18.14.1
No response
this.cacheManager.set(messageCacheKey, messageCount, { ttl: 60 });
Doesn't set correct TTL.
โโ @nestjs/[email protected]
โโ [email protected]
https://github.com/nestjs/cache-manager/tree/master/lib
No response
Sets TTL to 60 seconds
2.1.0
10.0.0
16.18.1
No response
Currently, we have implemented Redis with Cache Manager in our project. The Redis password is stored in a key vault and is updated monthly. Once the password is updated in the key vault, Redis throws a WRONGPASS error, causing the app to crash. Restarting the server is the only fix we have now.
Is it possible to re-register with the new configuration in app.module.ts
, or is there another way to handle this?
The error is as follows
WRONGPASS invalid username-password pair
"stack":[[{"command":"AUTH","args":["ere22dwdwqq"],"code":"WRONGPASS"}]]}
cache-manager-redis-store : 2.0.0
redis: 4.6.13
code is similar to this
@module({
imports: [
CacheModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService, KeyVaultService],
useFactory: async (configService: ConfigService, keyVaultService: KeyVaultService) => ({
store: redisStore,
socket: {
tls: true,
noDelay: true,
},
url: host:port/15,
password: 'await getPassWord(configService, keyVaultService),
}),
isGlobal: true,
}),
],
})
export class AppModule {
constructor(@Inject(CACHE_MANAGER) cacheManager) {
const client = cacheManager?.store?.getClient();
client.on('error', (error) => {
console.error( Redis error
, error);
});
client.on('connect', () => console.log(Redis is connecting
));
client.on('reconnecting', () =>
console.log( Redis is reconnecting
),
);
client.on('ready', () => console.log(Redis is ready
));
client.on('end', () => console.log( Redis is end
));
}}
nil
nil
reconnect redis with updated password
2.2.2
10.3.2
v16.20.2
No response
I have a helper function that creates the CacheModule dynamically based on some input. This function is called multiple times for different modules that rely on CacheModule.
The CacheModule however is not loading the settings correctly. Only one of the settings set are loaded and applied to all other modules using the same function.
function:
export function createCacheModule(options: CreateCacheModuleOptions) {
options.inject = [ConfigService, ...(options.inject || [])];
if (options.useFactory) {
const inputFactory = options.useFactory;
options.useFactory = async (configService: ConfigService) => {
const opts = await inputFactory(configService);
console.log({ opts });
return opts;
};
}
return CacheModule.registerAsync(options);
}
in the second screenshot you can see that only the useFactory
of AModule gets called and BModule gets the same config from AModule even though they are created differently.
https://github.com/GustavoKatel/nestjs-cache-module-test
npm ci
npm run start
I expected the ttl and all other settings to be different for in BModule, but insteead BModule got the same settings from AModule (see screenshots above)
2.1.1
10.2.8
21.1.0
No response
How can use cahce with enableVersioning?
When I have a version that I know the value of the controller version with the header, it doesn't work properly because of the cache
No response
work with enable versioning
2.2.2
No response
No response
No response
The modules providers are not found even though the module is specified as global.
https://stackblitz.com/edit/nestjs-typescript-starter-j7sze2?file=src%2Fapp.module.ts&terminal=start
Stackblitz -
Error: Nest can't resolve dependencies of the SubService (?). Please make sure that the argument "CACHE_MANAGER" at index [0] is available in the SubModule context.
Potential solutions:
The modules providers work like register
2.2.1
10.3.1
18
No response
Technically, the code supports multicaching, as written here: https://github.com/nestjs/cache-manager/blob/master/lib/cache.providers.ts#L53-L59
However, the types set on the register function do not indicate any sort of array input support.
There's also no mention of multicaching support in the documentation
https://github.com/nestjs/cache-manager/blob/master/lib/cache.providers.ts#L53-L59
No response
Multicaching should be supported by the register
and registerAsync
methods.
2.0.1
10.0.5
No response
No response
I have the following code that configures CacheModule with an in-memory or redis store depending on the environment variable configuration.
import { CacheModule } from '@nestjs/cache-manager';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { redisStore } from 'cache-manager-redis-yet';
import * as path from 'path';
import { ConfigSchema } from './config.schema';
import { validator } from './validator';
@Module({
imports: [
CacheModule.registerAsync({
imports: [
ConfigModule.forRoot({
envFilePath: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV}`,
),
validate: validator(ConfigSchema, (env: Record<string, unknown>) => ({
driver: env.CACHE_DRIVER,
url: env.CACHE_REDIS_URL,
})),
}),
],
useFactory: async (config: ConfigService<ConfigSchema>) => {
const driver = config.getOrThrow('driver', { infer: true });
if (driver === 'in-memory') return {};
if (driver === 'redis') {
return await redisStore({
url: config.getOrThrow('url', { infer: true }),
});
}
throw new Error(`incompatible option for driver: ${driver}`);
},
inject: [ConfigService],
}),
],
exports: [CacheModule],
})
export class CacheInfrastructureModule {}
When driver is redis, I get the following stack trace:
[Nest] 12331 - 27/02/2024, 19:18:57 ERROR [ExceptionHandler] ttl must be a positive integer if specified
TypeError: ttl must be a positive integer if specified
at new LRUCache (/Users/matias/projects/services-nuvem-pago-commons/node_modules/cache-manager/node_modules/lru-cache/src/index.ts:1130:15)
at memoryStore (/Users/matias/projects/services-nuvem-pago-commons/node_modules/cache-manager/dist/stores/memory.js:27:22)
at Object.caching (/Users/matias/projects/services-nuvem-pago-commons/node_modules/cache-manager/dist/caching.js:11:48)
at cachingFactory (/Users/matias/projects/services-nuvem-pago-commons/node_modules/@nestjs/cache-manager/dist/cache.providers.js:41:37)
at InstanceWrapper.useFactory [as metatype] (/Users/matias/projects/services-nuvem-pago-commons/node_modules/@nestjs/cache-manager/dist/cache.providers.js:48:19)
at Injector.instantiateClass (/Users/matias/projects/services-nuvem-pago-commons/node_modules/@nestjs/core/injector/injector.js:354:55)
at callback (/Users/matias/projects/services-nuvem-pago-commons/node_modules/@nestjs/core/injector/injector.js:56:45)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Injector.resolveConstructorParams (/Users/matias/projects/services-nuvem-pago-commons/node_modules/@nestjs/core/injector/injector.js:136:24)
at Injector.loadInstance (/Users/matias/projects/services-nuvem-pago-commons/node_modules/@nestjs/core/injector/injector.js:61:13)
Simplifying the useFactory
function to always create redis, I get this error:
useFactory: async (config: ConfigService<ConfigSchema>) => {
return await redisStore({
url: config.getOrThrow('url', { infer: true }),
});
},
src/shared/infrastructure/cache/cache.module.ts:24:7 - error TS2322: Type '(config: ConfigService<ConfigSchema>) => Promise<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/g...' is not assignable to type '(...args: any[]) => CacheModuleOptions<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/...'.
Type 'Promise<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); ... 15 m...' is not assignable to type 'CacheModuleOptions<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"...'.
Type 'Promise<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); ... 15 m...' is not assignable to type 'Promise<CacheModuleOptions<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CON...'.
Type 'RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); ... 15 more ...;...' is not assignable to type 'CacheModuleOptions<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"...'.
Type 'RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); ... 15 more ...;...' is not assignable to type 'CacheManagerOptions'.
Types of property 'ttl' are incompatible.
Type '(key: string) => Promise<number>' is not assignable to type 'number'.
24 useFactory: async (config: ConfigService<ConfigSchema>) => {
~~~~~~~~~~
node_modules/@nestjs/cache-manager/dist/interfaces/cache-module.interface.d.ts:42:5
42 useFactory?: (...args: any[]) => Promise<CacheModuleOptions<StoreConfig>> | CacheModuleOptions<StoreConfig>;
~~~~~~~~~~
The expected type comes from property 'useFactory' which is declared here on type 'CacheModuleAsyncOptions<RedisStore<RedisClientType<{ graph: { CONFIG_GET: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG_GET"); configGet: typeof import("/Users/matias/projects/services-nuvem-pago-commons/node_modules/@redis/graph/dist/commands/CONFIG...'
Libs:
https://github.com/matiasgarcia/nestjs-advanced-architecture
No response
Should work
2.2.1
9.4.1
20.9.0
No response
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
docker-compose.yml
package.json
@commitlint/cli 19.3.0
@commitlint/config-angular 19.3.0
@nestjs/common 10.3.10
@nestjs/core 10.3.10
@nestjs/platform-express 10.3.10
@nestjs/testing 10.3.10
@types/jest 29.5.12
@types/node 20.14.11
@types/supertest 6.0.2
@typescript-eslint/eslint-plugin 7.16.1
@typescript-eslint/parser 7.16.1
cache-manager 5.7.3
cache-manager-redis-store ^3.0.1
eslint 8.57.0
eslint-config-prettier 9.1.0
eslint-plugin-import 2.29.1
husky 9.1.0
jest 29.7.0
lint-staged 15.2.7
prettier 3.3.3
reflect-metadata 0.2.2
release-it 17.6.0
rimraf 6.0.1
rxjs 7.8.1
supertest 7.0.0
ts-jest 29.2.2
typescript 5.5.3
@nestjs/common ^9.0.0 || ^10.0.0
@nestjs/core ^9.0.0 || ^10.0.0
cache-manager <=5
rxjs ^7.0.0
The issue can actually be observed in #407, which tries to update to cache-manager v5.6.0
. See this CI step.
Not only it'd be great to be able to use cache-manager
's latest version, but also @nestjs/cache-manager
currently depends on version <= 5, which breaks with 5.6.0
.
No response
Depending on cache-manager v5.6.0
does not raise an error.
2.2.2
10
20
No response
Node cache manager provides the ability to pass redisInstance , this can be utilized to use a existing redis connection for cache
https://github.com/dabroek/node-cache-manager-ioredis?tab=readme-ov-file#use-an-external-redis-instance
CacheModule.registerAsync({
imports: [RedisModule],
inject: [RedisService],
useFactory: (redisService: RedisService) => ({
redisInstance: redisService.getClient(),
store: redisStore,
}),
}),
a new connection is opened on using the above code
https://gist.github.com/saurabh-vt/e027ce57bfa3897d16bcb4888b553ad4
initilaize cache manager with redis store
import { redisStore } from 'cache-manager-ioredis-yet';
import type { RedisOptions } from 'ioredis';
create a redisService and inject its instance in the cache-manager
cache manager should not open a new connection
^2.2.1
^10.0.2
v18.18.0
No response
Any time you want to cache key based on request you need to manually use cacheManager.
For example I have jwt token which is passed in the header and it has some value I need to use in cache key. For this I need to manually create cache object
It would be nice @Cache
to also accept callback
Example:
@Cache((ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user?.groupId;
})
No response
Ease of use
for now we inject cacheManager in this way
import { CACHE_MANAGER} from '@nestjs/cache-manager';
import { Cache} from 'cache-manager';
@Controller()
export class AsyncRegisterController {
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
which is hard to remember or code, because:
The Cache
class is imported from the cache-manager
, while CACHE_MANAGER
token from the @nestjs/cache-manager
package.
we can simply wrap the Cache
from cache-manager
with
import { Cache } from "cache-manager";
export type NestCache = Cache;
export const CACHE_MANAGER = 'CACHE_MANAGER';
export const NestCache = CACHE_MANAGER;
this solution is not following correct structure, just to demonstrate my idea
existing code will not be affected, all we need to do is to update documentation and mark CACHE_MANAGER as deprecated?
the motivation is that we can simplify our injection code to
import { NestCache } from '@nestjs/cache-manager';
@Controller()
export class AsyncRegisterController {
constructor(@Inject(NestCache) private cacheManager: NestCache) {}
which is much easier and cleanner
and even more, we can avoid the @Inject(NestCache)
by make NestCache a class that implement cache-manager's Cache
I often use console commands for long running jobs such as data migrations. I also have some workers that run in a headless Nest application.
In both instances, I occasionally have issues where the Redis cache client throws an ETIMEDOUT
error. This has the effect of crashing the entire program, and no amount of try/catching seems to catch the error.
I believe the correct way to deal with this is to set up an event listener on the redis client itself, however I have not been able to find a way to get the client once it's been instantiated.
Unless I'm missing something, there is no opportunity to set up an error listener in the following example code:
CacheModule.registerAsync<RedisClientOptions>({
useFactory: async () => {
const config = await getRedisConfig();
return {
...config,
store: redisStore,
};
},
}),
Being able to grab the client and set up listeners somewhere before it is used seems to be important. Ideally one could set up listeners at various touchpoints:
.on()
method) at runtimeEvent listeners may be specific to the Redis client, in which case this would be a better request for that library.
A possible API
Setting up listeners at config time:
CacheModule.registerAsync<RedisClientOptions>({
useFactory: async () => {
const config = await getRedisConfig();
return {
...config,
store: redisStore,
on: {
error: globalCacheErrorHandler,
// other event listeners
}
};
},
}),
Setting up listeners at run time
@Injectable()
export class CacheService {
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {
this.cacheManager.on('error', this.handleCacheError);
}
private handleCacheError(err: Error) {
// ....
}
}
As it stands, it's impossible to react to events emitted by the underlying client.
Set ttl
via this.cacheManager.set
is not working when ttl
is set in CacheModule.registerAsync
as global. ttl
is always set as the global value.
https://github.com/nestjs/cache-manager
ttl
set to 100
in CacheModule.registerAsync
as global:import { redisStore } from 'cache-manager-redis-store';
CacheModule.registerAsync<RedisClientOptions>({
isGlobal: true,
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
store: redisStore,
url: configService.get('REDIS_URL'),
password: configService.get('REDIS_PASS'),
ttl: 100,
}),
}),
ttl
set to 200
in xx.service.ts
:this.cacheManager.set(
'key',
'value',
200,
)
Check in redis client tool, TTL
is 200
1.0.0
9.0.0
16.17.0
No response
Please expose the error detail
expose the exception detail like message.
No response
User needs to debug why the cache not works
When applying the CacheInterceptor on endpoints and returning classes that use class-validator decorators, the application of the @Excluded()
decorator doesn't seem to exclude the attribute in the cached response. In the non-cached response it works as expected.
https://github.com/nestjs/cache-manager
@Excluded()
decorator applied on an attribute. @UseInterceptors(CacheInterceptor)
@CacheTTL(30000)
@Get('/test')
test() {
return this.testService.getResult();
}
Check the initial response which should NOT return the excluded attribute, as expected. (non-cached response)
Check the second response which should NOT return the excluded attribute, but surprisingly, the cache is not taking this into account and it also returns the excluded attribute. (cached response)
The attribute exclusion should also apply to the cached response.
1.0.0
9.4.0
18.13.0
No response
As per documentation , for using the redis store with CacheModule ( exported from @nestjs/cache-manager) , we provide the value for store manually i.e. redisStore ( exported from cache-maanger-redis-store), but there's no type "Store" present in CacheMangerOptions property of CacheModule.register() method . "Store" is the property exported from 'cache-manager" in redisStore.
CacheModule.register<RedisClientOptions>({ store: redisStore, host: 'localhost', // Redis server host port: 6379, // Redis server port }),
Current interface for CacheMangerOptions
`export interface CacheManagerOptions {
store?: string | CacheStoreFactory | CacheStore;
ttl?: number;
max?: number;
isCacheableValue?: (value: any) => boolean;
}`
https://github.com/no91one/nestjs-redis.git
npm i
nest start --watch
export interface CacheManagerOptions {
store?: string | CacheStoreFactory | CacheStore | Store;
host?:string;
port?:number;
ttl?: number;
max?: number;
isCacheableValue?: (value: any) => boolean;
}
2.1.0
10.0.0
18.16.1
No response
Currently im using redis server with multiple project, when i need to clean all cache related project A for eg, it its quite hard because we can't identify which cache belong to.
it will be good if we have the cache prefix that is configurable via module for example we can set to nestjs:*
so when we need to delete the cache, we can delete it by prefix and the other cache that is not related to a specific project is not deleted
No response
same as the solution
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.