Skip to content

Instantly share code, notes, and snippets.

@green3g
Created May 4, 2023 20:02
Show Gist options
  • Save green3g/1c6417a524a28b8093135005e941b731 to your computer and use it in GitHub Desktop.
Save green3g/1c6417a524a28b8093135005e941b731 to your computer and use it in GitHub Desktop.
import { Application, HookContext } from '@feathersjs/feathers';
import Redis, {RedisOptions} from 'ioredis';
import crypto from 'crypto';
import Cache from 'ioredis-cache';
import logger from '../../logger';
export const ONE_HOUR = 3600;
export const ONE_DAY = ONE_HOUR * 24;
export const ONE_WEEK = ONE_DAY * 7;
export interface IAppRedisOptions extends RedisOptions {
appKey: string;
}
export const defaultRedisOptions: IAppRedisOptions = {
keyPrefix: 'cache_',
appKey: 'cache',
};
export function redisCache(opt: IAppRedisOptions){
return function(app: Application){
opt = {
...defaultRedisOptions,
...opt,
};
logger.info({msg: 'Initializing cache', opt});
const redis = new Redis(opt);
const cache = new Cache(redis);
const appKey = opt.appKey || 'redis';
app.set(appKey, cache);
};
}
export function getHash(context: HookContext): string{
const hashParams = {
query: context.params.query,
paginate: context.params.paginate,
id: context.id,
};
const hash = crypto.createHash('sha256').update(JSON.stringify(hashParams)).digest('hex');
return hash;
}
export function getPrefix(context: HookContext): string{
const prefix = context.path.replace(/\//g, '_');
return prefix;
}
export function getKey(context: HookContext): string{
const prefix = getPrefix(context);
const hash = getHash(context);
return `${prefix}__${hash}`;
}
export function beforeHook(appKey: string){
return async (context: HookContext) => {
const cache = context.app.get(appKey) as Cache;
if(!cache){
logger.error('Cache not initialized with provided key: ' + appKey);
}
context.params.cacheKey = getKey(context);
const result = await cache.getCache(context.params.cacheKey);
if (result) {
context.params.cacheHit = true;
logger.info({msg: 'Cache hit', cacheKey: context.params.cacheKey});
context.result = result;
return context;
}
logger.info({msg: 'Cache miss', cacheKey: context.params.cacheKey});
return context;
};
}
export function afterHook(appKey: string, expires = ONE_HOUR){
return async (context: HookContext) => {
const cache = context.app.get(appKey) as Cache;
if(!cache){
logger.error('Cache not initialized with provided key: ' + appKey);
return;
}
if(!context.params.cacheHit){
await cache.setCache(context.params.cacheKey, context.result, expires);
logger.info({msg: 'Cache updated', cacheKey: context.params.cacheKey});
}
return context;
};
}
export function purgeCacheHook(appKey: string, path?: string){
return async (context: HookContext) => {
const cache = context.app.get(appKey) as Cache;
if(!cache){
logger.error('Cache not initialized with provided key: ' + appKey);
return;
}
const purgePrefix = path || getPrefix(context);
await cache.deletePattern(`${purgePrefix}*`);
logger.info({msg: 'Cache purged', prefix: purgePrefix});
return context;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment