Skip to content

Instantly share code, notes, and snippets.

@ctrlShiftBryan
Created July 14, 2022 17:38
Show Gist options
  • Save ctrlShiftBryan/25587418831f0a9d50d1c5dda3f67ed9 to your computer and use it in GitHub Desktop.
Save ctrlShiftBryan/25587418831f0a9d50d1c5dda3f67ed9 to your computer and use it in GitHub Desktop.
import { createClient, RedisClientType, RedisModules, RedisScripts } from '@node-redis/client';
import { getFromCache } from './cache.server';
describe('Name of the group', () => {
let client : RedisClientType<RedisModules, RedisScripts>;
beforeAll(async () => {
client = createClient({ url: process.env.REDIS_URL });
await client.connect();
});
beforeEach(async () => {
await client.flushAll();
});
it('it should return result of promise', async () => {
const res = await getFromCache({ promise: async () => ({ call: 1 }), term: 'test', maxAge: 1, client });
expect(res).toEqual({ call: 1 });
});
it('it should return cached if not stale', async () => {
const res = await getFromCache({ promise: async () => ({ call: 1 }), term: 'test', maxAge: 1, client });
expect(res).toEqual({ call: 1 });
// it should return call from first time
const futureDate = new Date().getTime() + 100_000;
const res2 = await getFromCache({ promise: async () => ({ call: 2 }), term: 'test', maxAge: 1, client, now: futureDate });
expect(res2).toEqual({ call: 1 });
expect(res).toStrictEqual(res2);
});
it('it should only return stale once', async () => {
// first call not cached
const res = await getFromCache({ promise: async () => ({ call: 1 }), term: 'test', maxAge: 1, client });
expect(res).toEqual({ call: 1 });
// it should return stale the first time it's called and is stale
const futureDate = new Date().getTime() + 100_000;
const res2 = await getFromCache({ promise: async () => ({ call: 2 }), term: 'test', maxAge: 1, client, now: futureDate });
expect(res2).toEqual({ call: 1 });
expect(res).toStrictEqual(res2);
const futureDate2 = new Date().getTime() + 200_000;
// it should return previous call value since it was stale but should have re-cached
const res3 = await getFromCache({ promise: async () => ({ call: 3 }), term: 'test', maxAge: 1, client, now: futureDate2 });
expect(res3).toEqual({ call: 2 });
});
afterAll(async () => {
await client.quit();
});
});
/* eslint-disable no-console */
import { createClient, RedisClientType, RedisModules, RedisScripts } from '@node-redis/client';
export async function clearFromCache(term: string): Promise<any> {
const client = createClient({ url: process.env.REDIS_URL });
await client.connect();
const result = await client.del(term);
return result;
}
export type getFromCacheParams = {
promise: () => Promise<any>,
term: string,
maxAge: number,
now?: number,
client: RedisClientType<RedisModules, RedisScripts>,
}
export async function getFromCache(params: getFromCacheParams): Promise<any> {
const { promise, term, maxAge, client } = params;
const result = await client.get(term);
const now = params.now || new Date().getTime();
// if its in redis
if (result) {
// before returning check if its expired
const data = JSON.parse(result);
const miliseconds = now - data.time;
const age = Math.round(miliseconds / 60_000);
const expired = age >= maxAge;
const res = { ...data, age, expired };
// reload but don't wait if expired
if (expired) {
console.log('Cache expired, reloading...');
promise().then((data: any) => { client.set(term, JSON.stringify({ term: data, time: now })); });
}
console.log('Cache hit!');
// return the term
return res.term;
}
console.log('Cache miss!');
// if its not in redi call the promise to get it and save to redis
const json = await promise();
client.set(term, JSON.stringify({ term: json, time: now }));
return json;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment