forked from triggerdotdev/trigger.dev
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache.ts
More file actions
106 lines (87 loc) · 2.62 KB
/
cache.ts
File metadata and controls
106 lines (87 loc) · 2.62 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { SemanticInternalAttributes } from "@trigger.dev/core/v3";
import { tracer } from "./tracer.js";
export type CacheMetadata = {
createdTime: number;
ttl?: number | null;
};
export type CacheEntry<Value = unknown> = {
metadata: CacheMetadata;
value: Value;
};
export type Eventually<Value> = Value | null | undefined | Promise<Value | null | undefined>;
export type CacheStore<Value = any> = {
name?: string;
get: (key: string) => Eventually<CacheEntry<Value>>;
set: (key: string, value: CacheEntry<Value>) => unknown | Promise<unknown>;
delete: (key: string) => unknown | Promise<unknown>;
};
export type CacheFunction = <Value>(
cacheKey: string,
fn: () => Promise<Value> | Value
) => Promise<Value> | Value;
export class InMemoryCache<Value = any> {
private _cache: Map<string, CacheEntry<Value>> = new Map();
get(key: string): Eventually<CacheEntry<Value>> {
return this._cache.get(key);
}
set(key: string, value: CacheEntry<Value>): unknown {
this._cache.set(key, value);
return undefined;
}
delete(key: string): unknown {
this._cache.delete(key);
return undefined;
}
}
/**
* Create a cache function that uses the provided store to cache values. Using InMemoryCache is safe because each task run is isolated.
* @param store
* @returns
*/
export function createCache(store: CacheStore): CacheFunction {
return function cache<Value>(
cacheKey: string,
fn: () => Promise<Value> | Value
): Promise<Value> | Value {
return tracer.startActiveSpan("cache", async (span) => {
span.setAttribute("cache.key", cacheKey);
span.setAttribute(SemanticInternalAttributes.STYLE_ICON, "device-sd-card");
const cacheEntry = await store.get(cacheKey);
if (cacheEntry) {
span.updateName(`cache.hit ${cacheKey}`);
return cacheEntry.value;
}
span.updateName(`cache.miss ${cacheKey}`);
const value = await tracer.startActiveSpan(
"cache.getFreshValue",
async (span) => {
return await fn();
},
{
attributes: {
"cache.key": cacheKey,
[SemanticInternalAttributes.STYLE_ICON]: "device-sd-card",
},
}
);
await tracer.startActiveSpan(
"cache.set",
async (span) => {
await store.set(cacheKey, {
value,
metadata: {
createdTime: Date.now(),
},
});
},
{
attributes: {
"cache.key": cacheKey,
[SemanticInternalAttributes.STYLE_ICON]: "device-sd-card",
},
}
);
return value;
});
};
}