@reactionary/core 0.9.6 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cache/redis-cache.js +50 -14
- package/package.json +3 -3
- package/src/cache/redis-cache.d.ts +6 -3
package/cache/redis-cache.js
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createClient } from "redis";
|
|
2
2
|
import { getReactionaryCacheMeter } from "../metrics/metrics.js";
|
|
3
3
|
class RedisCache {
|
|
4
4
|
redis;
|
|
5
|
+
connectPromise;
|
|
5
6
|
meter = getReactionaryCacheMeter();
|
|
6
|
-
constructor() {
|
|
7
|
-
|
|
7
|
+
constructor(redisUrl = process.env["REDIS_URL"]) {
|
|
8
|
+
if (!redisUrl) {
|
|
9
|
+
throw new Error("REDIS_URL is required");
|
|
10
|
+
}
|
|
11
|
+
this.redis = createClient({
|
|
12
|
+
url: redisUrl
|
|
13
|
+
});
|
|
14
|
+
this.redis.on("error", (err) => {
|
|
15
|
+
console.error("Redis error", err);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async client() {
|
|
19
|
+
if (!this.connectPromise) {
|
|
20
|
+
this.connectPromise = this.redis.connect();
|
|
21
|
+
}
|
|
22
|
+
return this.connectPromise;
|
|
8
23
|
}
|
|
9
24
|
async get(key, schema) {
|
|
10
25
|
if (!key) {
|
|
11
26
|
return null;
|
|
12
27
|
}
|
|
13
|
-
const
|
|
28
|
+
const redis = await this.client();
|
|
29
|
+
const serialized = await redis.get(key);
|
|
30
|
+
if (serialized === null) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
let unvalidated;
|
|
34
|
+
try {
|
|
35
|
+
unvalidated = JSON.parse(serialized);
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
14
39
|
const parsed = schema.safeParse(unvalidated);
|
|
15
40
|
if (parsed.success) {
|
|
16
41
|
this.meter.hits.add(1, {
|
|
@@ -24,34 +49,45 @@ class RedisCache {
|
|
|
24
49
|
if (!key) {
|
|
25
50
|
return;
|
|
26
51
|
}
|
|
52
|
+
const redis = await this.client();
|
|
27
53
|
const serialized = JSON.stringify(value);
|
|
28
|
-
const multi =
|
|
29
|
-
multi.set(key, serialized, {
|
|
54
|
+
const multi = redis.multi();
|
|
55
|
+
multi.set(key, serialized, {
|
|
56
|
+
EX: options.ttlSeconds
|
|
57
|
+
});
|
|
30
58
|
for (const depId of options.dependencyIds) {
|
|
31
|
-
multi.
|
|
59
|
+
multi.sAdd(`dep:${depId}`, key);
|
|
32
60
|
}
|
|
33
|
-
|
|
61
|
+
await multi.exec();
|
|
62
|
+
this.meter.items.record(await redis.dbSize(), {
|
|
34
63
|
"labels.cache_type": "redis"
|
|
35
64
|
});
|
|
36
|
-
await multi.exec();
|
|
37
65
|
}
|
|
38
66
|
async invalidate(dependencyIds) {
|
|
67
|
+
const redis = await this.client();
|
|
39
68
|
for (const id of dependencyIds) {
|
|
40
69
|
const depKey = `dep:${id}`;
|
|
41
|
-
const keys = await
|
|
70
|
+
const keys = await redis.sMembers(depKey);
|
|
42
71
|
if (keys.length > 0) {
|
|
43
|
-
await
|
|
72
|
+
await redis.del(keys);
|
|
44
73
|
}
|
|
45
|
-
await
|
|
74
|
+
await redis.del(depKey);
|
|
46
75
|
}
|
|
47
|
-
this.meter.items.record(await
|
|
76
|
+
this.meter.items.record(await redis.dbSize(), {
|
|
48
77
|
"labels.cache_type": "redis"
|
|
49
78
|
});
|
|
50
79
|
}
|
|
51
80
|
async clear() {
|
|
52
|
-
|
|
81
|
+
const redis = await this.client();
|
|
82
|
+
this.meter.items.record(await redis.dbSize(), {
|
|
53
83
|
"labels.cache_type": "redis"
|
|
54
84
|
});
|
|
85
|
+
await redis.flushDb();
|
|
86
|
+
}
|
|
87
|
+
async close() {
|
|
88
|
+
if (this.redis.isOpen) {
|
|
89
|
+
await this.redis.quit();
|
|
90
|
+
}
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
export {
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/core",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"zod": "4.1.9",
|
|
9
|
-
"@upstash/redis": "^1.34.9",
|
|
10
9
|
"@opentelemetry/api": "^1.9.0",
|
|
11
10
|
"node-object-hash": "^3.1.1",
|
|
12
11
|
"vitest": "^4.0.9",
|
|
13
|
-
"@nx/vite": "22.4.5"
|
|
12
|
+
"@nx/vite": "22.4.5",
|
|
13
|
+
"redis": "^5.12.1"
|
|
14
14
|
},
|
|
15
15
|
"sideEffects": false
|
|
16
16
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createClient } from 'redis';
|
|
2
2
|
import type { Cache, CacheEntryOptions } from './cache.interface.js';
|
|
3
3
|
import type * as z from 'zod';
|
|
4
4
|
export declare class RedisCache implements Cache {
|
|
5
|
-
protected redis:
|
|
5
|
+
protected redis: ReturnType<typeof createClient>;
|
|
6
|
+
protected connectPromise?: Promise<ReturnType<typeof createClient>>;
|
|
6
7
|
protected meter: import("../metrics/metrics.js").ReactionaryCacheMetrics;
|
|
7
|
-
constructor();
|
|
8
|
+
constructor(redisUrl?: string | undefined);
|
|
9
|
+
protected client(): Promise<ReturnType<typeof createClient>>;
|
|
8
10
|
get<T>(key: string, schema: z.ZodType<T>): Promise<T | null>;
|
|
9
11
|
put(key: string, value: unknown, options: CacheEntryOptions): Promise<void>;
|
|
10
12
|
invalidate(dependencyIds: Array<string>): Promise<void>;
|
|
11
13
|
clear(): Promise<void>;
|
|
14
|
+
close(): Promise<void>;
|
|
12
15
|
}
|