@trieb.work/nextjs-turbo-redis-cache
Version:
The ultimate Redis caching solution for Next.js. Built for production-ready, large-scale projects, it delivers unparalleled performance and efficiency with features tailored for high-traffic applications.
62 lines (56 loc) • 1.95 kB
text/typescript
import { SyncedMap } from './SyncedMap';
export class DeduplicatedRequestHandler<
T extends (...args: [never, never]) => Promise<K>,
K,
> {
private inMemoryDeduplicationCache: SyncedMap<Promise<K>>;
private cachingTimeMs: number;
private fn: T;
constructor(
fn: T,
cachingTimeMs: number,
inMemoryDeduplicationCache: SyncedMap<Promise<K>>,
) {
this.fn = fn;
this.cachingTimeMs = cachingTimeMs;
this.inMemoryDeduplicationCache = inMemoryDeduplicationCache;
}
// Method to manually seed a result into the cache
seedRequestReturn(key: string, value: K): void {
const resultPromise = new Promise<K>((res) => res(value));
this.inMemoryDeduplicationCache.set(key, resultPromise);
setTimeout(() => {
this.inMemoryDeduplicationCache.delete(key);
}, this.cachingTimeMs);
}
// Method to handle deduplicated requests
deduplicatedFunction = (key: string): T => {
//eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
const dedupedFn = async (...args: [never, never]): Promise<K> => {
// If there's already a pending request with the same key, return it
if (
self.inMemoryDeduplicationCache &&
self.inMemoryDeduplicationCache.has(key)
) {
const res = await self.inMemoryDeduplicationCache
.get(key)!
.then((v) => structuredClone(v));
return res;
}
// If no pending request, call the original function and store the promise
const promise = self.fn(...args);
self.inMemoryDeduplicationCache.set(key, promise);
try {
const result = await promise;
return structuredClone(result);
} finally {
// Once the promise is resolved/rejected, remove it from the map
setTimeout(() => {
self.inMemoryDeduplicationCache.delete(key);
}, self.cachingTimeMs);
}
};
return dedupedFn as T;
};
}