MCPcopy Create free account
hub / github.com/Openpanel-dev/openpanel / cacheable

Function cacheable

packages/redis/cachable.ts:187–295  ·  view source on GitHub ↗
(
  fnOrName: T | string,
  fnOrExpireInSec: number | T,
  expireInSecOrOptions?: number | CacheableOptions,
  maybeOptions?: CacheableOptions
)

Source from the content-addressed store, hash-verified

185
186// Implementation for cacheable (Redis-only - async)
187export function cacheable<T extends (...args: any) => any>(
188 fnOrName: T | string,
189 fnOrExpireInSec: number | T,
190 expireInSecOrOptions?: number | CacheableOptions,
191 maybeOptions?: CacheableOptions
192) {
193 const name = typeof fnOrName === 'string' ? fnOrName : fnOrName.name;
194 const fn =
195 typeof fnOrName === 'function'
196 ? fnOrName
197 : typeof fnOrExpireInSec === 'function'
198 ? fnOrExpireInSec
199 : null;
200
201 let expireInSec: number | null = null;
202 let options: CacheableOptions = {};
203
204 // Parse parameters based on function signature
205 if (typeof fnOrName === 'function') {
206 // Overload 1: cacheable(fn, expireInSec, options?)
207 expireInSec = typeof fnOrExpireInSec === 'number' ? fnOrExpireInSec : null;
208 if (expireInSecOrOptions && typeof expireInSecOrOptions === 'object') {
209 options = expireInSecOrOptions;
210 }
211 } else {
212 // Overload 2: cacheable(name, fn, expireInSec, options?)
213 expireInSec =
214 typeof expireInSecOrOptions === 'number' ? expireInSecOrOptions : null;
215 if (maybeOptions) {
216 options = maybeOptions;
217 }
218 }
219
220 if (typeof fn !== 'function') {
221 throw new Error('fn is not a function');
222 }
223
224 if (typeof expireInSec !== 'number') {
225 throw new Error('expireInSec is not a number');
226 }
227
228 const cachePrefix = `cachable:${name}`;
229 const getKey = (...args: Parameters<T>) =>
230 `${cachePrefix}:${stringify(args)}`.replaceAll(/\s/g, '');
231
232 const lruCache = new LRUCache<string, any>({
233 max: CACHEABLE_LRU_MAX,
234 ttl: CACHEABLE_LRU_TTL_MS,
235 });
236
237 // L1 LRU (60s) + L2 Redis. clear() deletes Redis + local LRU; other nodes may serve stale from LRU for up to 60s.
238 const cachedFn = async (
239 ...args: Parameters<T>
240 ): Promise<Awaited<ReturnType<T>>> => {
241 const key = getKey(...args);
242
243 // L1: in-memory LRU first (offloads Redis on hot keys)
244 const lruHit = lruCache.get(key);

Callers 13

cachable.test.tsFile · 0.90
gsc.tsFile · 0.90
session.service.tsFile · 0.90
event.service.tsFile · 0.90
project.service.tsFile · 0.90
salt.service.tsFile · 0.90
clients.service.tsFile · 0.90
access.service.tsFile · 0.90
profile.service.tsFile · 0.90
sessions.tsFile · 0.90

Calls 6

getRedisCacheFunction · 0.90
shouldCacheFunction · 0.85
getKeyFunction · 0.70
setMethod · 0.45
catchMethod · 0.45
stringifyMethod · 0.45

Tested by

no test coverage detected