@@ -2,9 +2,11 @@ import { getRedisCache } from "./redis";
22
33const logger = console ;
44
5+ const activeRevalidations = new Map < string , Promise < void > > ( ) ;
6+
57const stringifyRegex = / ^ \d { 4 } - \d { 2 } - \d { 2 } T \d { 2 } : \d { 2 } : \d { 2 } .* Z $ / ;
68
7- interface CacheOptions {
9+ type CacheOptions = {
810 expireInSec : number ;
911 prefix ?: string ;
1012 serialize ?: ( data : unknown ) => string ;
@@ -47,9 +49,9 @@ export async function getCache<T>(
4749
4850 if ( staleWhileRevalidate ) {
4951 const ttl = await redis . ttl ( key ) ;
50- if ( ttl < staleTime ) {
52+ if ( ttl < staleTime && ! activeRevalidations . has ( key ) ) {
5153 // Return stale data and revalidate in background
52- fn ( )
54+ const revalidationPromise = fn ( )
5355 . then ( async ( freshData : T ) => {
5456 if ( freshData !== undefined && freshData !== null ) {
5557 const redis = getRedisCache ( ) ;
@@ -61,7 +63,11 @@ export async function getCache<T>(
6163 `Background revalidation failed for key ${ key } :` ,
6264 error
6365 ) ;
66+ } )
67+ . finally ( ( ) => {
68+ activeRevalidations . delete ( key ) ;
6469 } ) ;
70+ activeRevalidations . set ( key , revalidationPromise ) ;
6571 }
6672 }
6773
@@ -74,7 +80,7 @@ export async function getCache<T>(
7480 }
7581 return data ;
7682 } catch ( error : unknown ) {
77- retries ++ ;
83+ retries += 1 ;
7884 if ( retries === maxRetries ) {
7985 logger . error (
8086 `Cache error for key ${ key } after ${ maxRetries } retries:` ,
@@ -157,9 +163,9 @@ export function cacheable<T extends (...args: any) => any>(
157163
158164 if ( staleWhileRevalidate ) {
159165 const ttl = await redis . ttl ( key ) ;
160- if ( ttl < staleTime ) {
166+ if ( ttl < staleTime && ! activeRevalidations . has ( key ) ) {
161167 // Return stale data and revalidate in background
162- fn ( ...args )
168+ const revalidationPromise = fn ( ...args )
163169 . then ( async ( freshData : Awaited < ReturnType < T > > ) => {
164170 if ( freshData !== undefined && freshData !== null ) {
165171 const redis = getRedisCache ( ) ;
@@ -171,7 +177,11 @@ export function cacheable<T extends (...args: any) => any>(
171177 `Background revalidation failed for function ${ fn . name } :` ,
172178 error
173179 ) ;
180+ } )
181+ . finally ( ( ) => {
182+ activeRevalidations . delete ( key ) ;
174183 } ) ;
184+ activeRevalidations . set ( key , revalidationPromise ) ;
175185 }
176186 }
177187
@@ -184,7 +194,7 @@ export function cacheable<T extends (...args: any) => any>(
184194 }
185195 return result ;
186196 } catch ( error : unknown ) {
187- retries ++ ;
197+ retries += 1 ;
188198 if ( retries === maxRetries ) {
189199 logger . error (
190200 `Cache error for function ${ fn . name } after ${ maxRetries } retries:` ,
0 commit comments