Closed xmlking closed 6 years ago
The way how internal CacheModule
works differ from any typical class-oriented cache. What you have proposed can be implemented by any 3rd-party package which doesn't necessarily have to be only Nest compatible. For now, there is no plan to provide such functionality directly from the nest packages.
are there any hooks to access underneath user configured cache store, so that we can implement custom annotations on top of cache store CacheModule
provides ?
Created this cache decorator
. any feedback appreciated
https://github.com/xmlking/ngx-starter-kit/blob/develop/apps/api/src/app/cache/cache.decorator.ts
Hey guys, I also have something familiar, called ngx-cacheable. It's literally a Typescript decorator which work with both Observables and Promises. It was initially inspired by some of my work with Angular, however recently I also made it so it can be used with Promises and already use it on both the client and server of one of my apps :) @kamilmysliwiec, did you have any plans on supporting such a decorator as a first class citizen in Nest? (btw, I absolutely love the framework, already used in a couple of my public-facing projects :))
Here is a simple @Cache
decorator with lru-cache
:
import LRU from 'lru-cache';
const cache = new LRU();
export function Cache({ key, ttl }: { key: string; ttl: number }) {
return function(
_target: Record<string, any>,
_propertyKey: string,
descriptor: PropertyDescriptor
) {
const method = descriptor.value;
descriptor.value = async function(...args: any[]) {
if (cache.get(key)) return cache.get(key);
const result = await method.apply(this, args);
cache.set(key, result, ttl);
return result;
};
};
}
usage:
@Cache({ key: 'admin_menu_count', ttl: 1000 * 60 * 5 })
private async getCachedCount() {
[...]
}
@iam4x nice hint 👍
The issue I discovered using it at controller methods which return an observable was that it caches the original observable instead of the resolved value. In my case I request some data from another api using the HttpService, it caches the observable and passes it to nest which will resolve the observable every time I call the controller method, which again results in an http request for each call.
So I slightly modified your solution to be able to cache the value of the observable using the default cache-manager
. Another modification I added was the option to calculate the ttl value during runtime by passing a function.
import * as cacheManager from 'cache-manager';
import {Logger} from '@nestjs/common';
import {of} from 'rxjs';
const memoryCache = cacheManager.caching({store: 'memory', max: 100, ttl: 10});
export function Cache({key, ttl}: {key?: string; ttl: number | Function}) {
return function(target: Record<string, any>, propertyKey: string, descriptor: PropertyDescriptor) {
if (!key) {
key = `${target.constructor.name}/${propertyKey.toString()}`;
}
const method = descriptor.value;
descriptor.value = async function(...args: any[]) {
const cachedItem = await memoryCache.get(key);
if (cachedItem) {
return of(cachedItem); // return the cached value as observable
}
const result = await method.apply(this, args).toPromise();
const calcTtl = typeof ttl === 'function' ? ttl() : ttl;
await memoryCache.set(key, result, {ttl: calcTtl});
return of(result); // return the value of the resolved result as observable
};
};
}
Usage at controller method level:
@Get('')
@Cache({
key: 'rush-hour',
ttl: function() {
// cache the value for the rest of the day because it gets once per day generated at midnight
const now = new Date();
return 24 * 60 * 60 - now.getHours() * 60 * 60 - now.getMinutes() * 60 - now.getSeconds();
},
})
getRushHour(): Observable<RushHourResponse> {
return this.rushHourService.find();
}
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
I'm submitting a...
Current behavior
Only cacheing implemented for controllers. missing auto cache invalidation
Expected behavior
proposed example:
Minimal reproduction of the problem with instructions
What is the motivation / use case for changing the behavior?
we like to control caching and cache invalidation for CRUD Services automatically, key can be derived from args e.g., https://github.com/havsar/node-ts-cache/blob/master/src/CacheDecorator.ts
Environment