1import * as _ from 'lodash-es' 4type CacheEntry<T> = { expAtMs: number, cacheVal: T } 6const memCacheH: Record<string, CacheEntry<unknown>> = {} 7const keysSortedByExp: string[] = [] 9type CacheFetchOpts<T> = { 12 cacheMissFn: () => Promise<T> 15export const cacheFetch = async <T,>({cacheKey, ttlMs, cacheMissFn}: CacheFetchOpts<T>): Promise<T> => { 18 const nowIdx = _.sortedIndexBy(keysSortedByExp, 'nowidx', (ckey) => { 19 if (ckey == 'nowidx') return now 20 if (!memCacheH[ckey]) { 21 throw new PtErr('!memCacheH[ckey]', {ckey, cacheKey, memCacheH, keysSortedByExp}) 23 return memCacheH[ckey].expAtMs 26 const delCount = nowIdx 27 const expiredKeys = keysSortedByExp.splice(0, delCount) 28 // console.log({delCount, expiredKeys}, _.map(keysSortedByExp, (ckey) => memCacheH[ckey].expAtMs)) 29 if (expiredKeys.length > 0) { 30 console.log(delCount, 'expired: ', expiredKeys.join(' ')) 31 _.each(expiredKeys, (ckey) => { 32 delete memCacheH[ckey] 36 const existingEntry = memCacheH[cacheKey] 38 return existingEntry.cacheVal as T 41 const cacheVal = await cacheMissFn() 47 memCacheH[cacheKey] = newEntry 49 const sortedIdx = _.sortedIndexBy(keysSortedByExp, cacheKey, (ckey) => { 50 if (!memCacheH[ckey]) { 51 console.log('!memCacheH[ckey]', {ckey, cacheKey, memCacheH, keysSortedByExp}) 53 return memCacheH[ckey].expAtMs 55 keysSortedByExp.splice(sortedIdx, 0, cacheKey)