-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcache.ts
More file actions
57 lines (52 loc) · 2.24 KB
/
cache.ts
File metadata and controls
57 lines (52 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { execute } from './execute';
import { CacheOptions, CacheStore } from '../common/models/executionCache.model';
import { generateHashId } from '../common/utils/crypto';
import { extractFunctionMetadata } from '../common/utils/functionMetadata';
import { MapCacheStore } from '../common/utils/mapStore';
export const cacheStoreKey = Symbol('execution-engine/cache');
/**
* Caches function results to avoid redundant expensive computations
* If the result is already cached, it returns the cached value; otherwise, it executes the function and stores the result.
*
* This is useful for optimizing expensive computations or API calls by reducing duplicate executions.
* @remarks
* - Errors are thrown immediately and **not cached** to allow retries.
*/
export async function executeCache<O>(
blockFunction: (...params: unknown[]) => O | Promise<O>,
inputs: Array<unknown> = [],
options: CacheOptions & { functionId: string }
): Promise<Promise<O> | O> {
const functionMetadata = extractFunctionMetadata(blockFunction);
const cacheKey = options.cacheKey?.({ metadata: functionMetadata, inputs }) ?? generateHashId(...inputs);
const ttl = typeof options.ttl === 'function' ? options.ttl({ metadata: functionMetadata, inputs }) : options.ttl;
let cacheStore: CacheStore | MapCacheStore<O>;
if (options.cacheManager) {
cacheStore = typeof options.cacheManager === 'function' ? options.cacheManager(this) : options.cacheManager;
} else {
cacheStore = new MapCacheStore<O>(this[cacheStoreKey], options.functionId);
}
const cachedValue: O = (await cacheStore.get(cacheKey)) as O;
if (typeof options.onCacheEvent === 'function') {
options.onCacheEvent({ ttl, metadata: functionMetadata, inputs, cacheKey, isCached: !!cachedValue, value: cachedValue });
}
if (cachedValue) {
return cachedValue;
} else {
return (execute.bind(this) as typeof execute)(
blockFunction.bind(this) as typeof blockFunction,
inputs,
[],
(res) => {
cacheStore.set(cacheKey, res as O, ttl);
if((cacheStore as MapCacheStore<O>).fullStorage) {
this[cacheStoreKey] = (cacheStore as MapCacheStore<O>).fullStorage;
}
return res;
},
(error) => {
throw error;
}
);
}
}