valkyries 0.1.0 → 0.1.2
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/README.md +2 -0
- package/dist/cache/mutations.d.mts.map +1 -1
- package/dist/cache/mutations.mjs +8 -6
- package/dist/cache/mutations.mjs.map +1 -1
- package/dist/clients.d.mts.map +1 -1
- package/dist/clients.mjs +16 -5
- package/dist/clients.mjs.map +1 -1
- package/dist/delete.d.mts.map +1 -1
- package/dist/delete.mjs +1 -3
- package/dist/delete.mjs.map +1 -1
- package/dist/dynamic-config/fields.d.mts.map +1 -1
- package/dist/dynamic-config/fields.mjs +35 -7
- package/dist/dynamic-config/fields.mjs.map +1 -1
- package/dist/rate-limiter.d.mts.map +1 -1
- package/dist/rate-limiter.mjs +4 -0
- package/dist/rate-limiter.mjs.map +1 -1
- package/docs/api.md +40 -0
- package/docs/bloom-filters.md +219 -0
- package/docs/cache.md +191 -0
- package/docs/clients.md +98 -0
- package/docs/dynamic-config.md +132 -0
- package/docs/events-and-metrics.md +99 -0
- package/docs/lua-scripts.md +45 -0
- package/docs/rate-limiter.md +136 -0
- package/docs/utilities.md +65 -0
- package/package.json +23 -22
package/docs/cache.md
CHANGED
|
@@ -17,3 +17,194 @@ Values larger than 2 KiB are gzip-compressed. Null results are cached with `null
|
|
|
17
17
|
`cacheGetByAny()` and `cacheGetByAnyBatch()` protect against stale miss writes by setting short-lived invalidation markers during delete operations.
|
|
18
18
|
|
|
19
19
|
Optional Bloom filter integration can skip authoritative-store calls for definite misses. If the Bloom filter is unavailable or not ready, cache reads fall back to the normal miss path.
|
|
20
|
+
|
|
21
|
+
## Import
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { ValkeyCache } from "valkyries";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
or:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { ValkeyCache } from "valkyries/cache";
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Constructor
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const cache = new ValkeyCache({ prefix: "users", ttlSeconds: 300 });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
type ValkeyCacheOptions<K = string> = {
|
|
41
|
+
prefix: string;
|
|
42
|
+
ttlSeconds: number;
|
|
43
|
+
nullTtlSeconds?: number;
|
|
44
|
+
mode?: "json" | "text" | "buffer";
|
|
45
|
+
staleTtlAge?: number;
|
|
46
|
+
bloomFilter?: ValkeyBloomFilter;
|
|
47
|
+
bloomFilterEnabled?: () => boolean;
|
|
48
|
+
client?: GlideClient;
|
|
49
|
+
keySerializer?: (key: K) => string;
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For non-string keys, `keySerializer` is required.
|
|
54
|
+
|
|
55
|
+
- `prefix`: namespace for this cache.
|
|
56
|
+
- `ttlSeconds`: TTL for non-null values.
|
|
57
|
+
- `nullTtlSeconds`: TTL for cached nulls. Defaults to `Math.max(1, Math.floor(ttlSeconds / 60))`.
|
|
58
|
+
- `mode`: serialization mode. Defaults to `json`.
|
|
59
|
+
- `staleTtlAge`: refresh-ahead threshold from `0` to `1`. Defaults to `0.9`.
|
|
60
|
+
- `bloomFilter`: optional negative-lookup Bloom filter.
|
|
61
|
+
- `bloomFilterEnabled`: optional per-call gate for Bloom filter checks.
|
|
62
|
+
- `client`: optional `@valkey/valkey-glide` client. Defaults to the package cache client.
|
|
63
|
+
- `keySerializer`: converts keys to strings before trimming and lowercasing.
|
|
64
|
+
|
|
65
|
+
The constructor throws when `prefix` is empty, `ttlSeconds` is not positive, or `staleTtlAge` is outside `0..1`.
|
|
66
|
+
|
|
67
|
+
## `cacheGetByAny(fn)`
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
cache.cacheGetByAny<T>(
|
|
71
|
+
fn: (key: K) => Promise<T | null | undefined>,
|
|
72
|
+
): (key: K) => Promise<T | null>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Returns a read-through single-key cache wrapper.
|
|
76
|
+
|
|
77
|
+
Behavior:
|
|
78
|
+
|
|
79
|
+
- Invalid, null, undefined, or empty serialized keys return `null`.
|
|
80
|
+
- Cache hits return the decoded value.
|
|
81
|
+
- Cached nulls return `null` without calling `fn`.
|
|
82
|
+
- Misses call `fn(key)`.
|
|
83
|
+
- `undefined` from `fn` is normalized to `null`.
|
|
84
|
+
- Miss results are written asynchronously when no invalidation marker is present.
|
|
85
|
+
- Stale hits can trigger asynchronous refresh-ahead.
|
|
86
|
+
|
|
87
|
+
## `cacheGetByAnyBatch(batchFn)`
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
cache.cacheGetByAnyBatch<T>(
|
|
91
|
+
batchFn: (keys: K[]) => Promise<Array<T | null | undefined>>,
|
|
92
|
+
): (keys: K[]) => Promise<Array<T | null>>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Returns a read-through batch cache wrapper.
|
|
96
|
+
|
|
97
|
+
Behavior:
|
|
98
|
+
|
|
99
|
+
- Input order and length are preserved.
|
|
100
|
+
- Invalid keys return `null` in their original output positions.
|
|
101
|
+
- Duplicate serialized keys are fetched once and scattered back to every duplicate position.
|
|
102
|
+
- `batchFn` is called only for real misses.
|
|
103
|
+
- `batchFn` must return an array with exactly the same length as its input.
|
|
104
|
+
- `undefined` values are normalized to `null`.
|
|
105
|
+
- Fetched values are written asynchronously when no invalidation marker is present.
|
|
106
|
+
- Stale hits can trigger asynchronous batch refresh-ahead.
|
|
107
|
+
|
|
108
|
+
## `get(key)`
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
cache.get(key: K): Promise<string | Buffer | Record<string, unknown> | null>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Reads a cache entry directly without calling a fallback function. Returns `null` for misses, invalid keys, cached nulls, and Bloom-filter negative lookups.
|
|
115
|
+
|
|
116
|
+
## `getBatch(keys)`
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
cache.getBatch(keys: K[]): Promise<Array<string | Buffer | Record<string, unknown> | null>>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Reads multiple cache entries directly. Output order and length match the input.
|
|
123
|
+
|
|
124
|
+
## `set(key, value, ttl?)`
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
cache.set(key: K, value: unknown, ttl?: number): Promise<void>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Writes a value directly.
|
|
131
|
+
|
|
132
|
+
- Positive `ttl` overrides the cache TTL for this entry.
|
|
133
|
+
- `null` and `undefined` values use `nullTtlSeconds`.
|
|
134
|
+
- Invalid keys are ignored.
|
|
135
|
+
- In `text` mode, `value` must be a string.
|
|
136
|
+
- In `buffer` mode, `value` must be a `Buffer`.
|
|
137
|
+
|
|
138
|
+
## `setBatch(entries)`
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
cache.setBatch(
|
|
142
|
+
entries: Array<{ key: K; value: unknown; ttl?: number }>,
|
|
143
|
+
): Promise<void>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Writes multiple values directly using a Valkey batch.
|
|
147
|
+
|
|
148
|
+
## `refreshById(aliases, fetchByKey)`
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
cache.refreshById<T>(
|
|
152
|
+
aliases: K[],
|
|
153
|
+
fetchByKey: (key: K) => Promise<T | null | undefined>,
|
|
154
|
+
): Promise<T | null>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Fetches fresh data once using the first valid alias, then writes the result to every valid alias. Use this when one entity can be addressed by several cache keys.
|
|
158
|
+
|
|
159
|
+
## `delete(...keys)`
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
cache.delete(...keys: K[]): Promise<number>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Deletes cache entries and writes short-lived invalidation markers so in-flight read-through writes do not repopulate stale data.
|
|
166
|
+
|
|
167
|
+
## `invalidateCacheGetByAny(...keys)`
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
cache.invalidateCacheGetByAny(...keys: K[]): Promise<number>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Alias for `delete(...keys)`.
|
|
174
|
+
|
|
175
|
+
## `invalidate()`
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
cache.invalidate(): Promise<void>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Deletes every cache key for this cache prefix.
|
|
182
|
+
|
|
183
|
+
## `ValkeyCache.invalidate(prefix, client?)`
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
ValkeyCache.invalidate(prefix: string, client?: GlideClient): Promise<void>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Deletes every cache key for `prefix`. Passing an empty prefix invalidates all cache namespaces visible to the client.
|
|
190
|
+
|
|
191
|
+
## `getKey(key)`
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
cache.getKey(key: K): string
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Returns the Valkey cache key for a logical key. Throws when the logical key serializes to an invalid cache key.
|
|
198
|
+
|
|
199
|
+
## Events
|
|
200
|
+
|
|
201
|
+
The cache emits:
|
|
202
|
+
|
|
203
|
+
- `cache:call` with cache name, batch flag, hit/miss/bloom-miss counts, and duration.
|
|
204
|
+
- `cache:hit` with `{ cacheName, keys, count }`.
|
|
205
|
+
- `cache:miss` with `{ cacheName, keys, count }`.
|
|
206
|
+
- `cache:bloom-miss` with `{ cacheName, keys, count }`.
|
|
207
|
+
- `cache:set` with `{ cacheName, keys }`.
|
|
208
|
+
- `cache:set-skipped` with `{ cacheName, keys }`.
|
|
209
|
+
- `cache:delete` with `{ cacheName, keys }`.
|
|
210
|
+
- `cache:invalidate` with `{ cacheName }`.
|
package/docs/clients.md
CHANGED
|
@@ -11,3 +11,101 @@ Connections are deduplicated by URL, read preference, and lazy-connect setting t
|
|
|
11
11
|
For libraries, tests, and multi-tenant services, pass a `GlideClient` directly to `ValkeyCache`, `ValkeyBloomFilter`, `DynamicConfig`, or `RateLimiter`.
|
|
12
12
|
|
|
13
13
|
Use `closeValkeyClients()` or `onGracefulShutdown()` to close package-managed clients and the dynamic-config pub/sub connection.
|
|
14
|
+
|
|
15
|
+
## Default Clients
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { cacheValkeyClient, rateLimiterValkeyClient, dynamicConfigValkeyClient } from "valkyries";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Default clients are created at module load:
|
|
22
|
+
|
|
23
|
+
- `cacheValkeyClient`: uses `VALKEY_CACHE_URL` or `VALKEY_URL`, reads from replicas when possible.
|
|
24
|
+
- `rateLimiterValkeyClient`: uses `VALKEY_RATE_LIMITER_URL`, `VALKEY_CACHE_URL`, or `VALKEY_URL`, and reads from primary.
|
|
25
|
+
- `dynamicConfigValkeyClient`: uses `VALKEY_DYNAMIC_CONFIG_URL` or `VALKEY_URL`, reads from replicas when possible.
|
|
26
|
+
|
|
27
|
+
## `ValkeyClientOptions`
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
type ValkeyClientOptions = {
|
|
31
|
+
readFrom?: "primary" | "preferReplica";
|
|
32
|
+
lazyConnect?: boolean;
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `readFrom`: Glide read preference.
|
|
37
|
+
- `lazyConnect`: whether Glide should connect lazily. Defaults to `true`.
|
|
38
|
+
|
|
39
|
+
## `urlsToClients`
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
const urlsToClients: Map<string, GlideClient>;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Registry of package-managed clients keyed by URL, read preference, and lazy-connect setting.
|
|
46
|
+
|
|
47
|
+
## `upsertValkeyClientByUrl(url, options?)`
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
upsertValkeyClientByUrl(
|
|
51
|
+
url: string,
|
|
52
|
+
options?: ValkeyClientOptions,
|
|
53
|
+
): Promise<GlideClient>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Returns an existing matching client or creates and stores a new one.
|
|
57
|
+
|
|
58
|
+
## `glideConfigFromUrl(url, options?)`
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
glideConfigFromUrl(url: string, options?: ValkeyClientOptions)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Builds a Glide client configuration from `redis://` or `rediss://` URLs.
|
|
65
|
+
|
|
66
|
+
Supported URL fields:
|
|
67
|
+
|
|
68
|
+
- host
|
|
69
|
+
- port
|
|
70
|
+
- username
|
|
71
|
+
- password
|
|
72
|
+
- TLS through `rediss://`
|
|
73
|
+
|
|
74
|
+
Throws `Invalid Valkey URL` for malformed URLs.
|
|
75
|
+
|
|
76
|
+
## Dynamic Config Pub/Sub Client
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
ensureDynamicConfigValkeySubscriptionClient(): Promise<GlideClient>
|
|
80
|
+
closeDynamicConfigValkeySubscriptionClient(): Promise<void>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`ensureDynamicConfigValkeySubscriptionClient()` creates or returns the shared pub/sub client subscribed to `dynamic-config:*`.
|
|
84
|
+
|
|
85
|
+
`closeDynamicConfigValkeySubscriptionClient()` unsubscribes and closes the shared pub/sub client.
|
|
86
|
+
|
|
87
|
+
## Pub/Sub Handlers
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
addPubSubMessageHandler(handler: (msg: PubSubMsg) => void): void
|
|
91
|
+
removePubSubMessageHandler(handler: (msg: PubSubMsg) => void): void
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Registers or removes handlers that receive dynamic-config pub/sub messages.
|
|
95
|
+
|
|
96
|
+
## Shutdown
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
closeValkeyClients(): Promise<void>
|
|
100
|
+
onGracefulShutdown(): Promise<void>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Both exports point to the same idempotent shutdown function. It closes all live dynamic configs, package-managed clients, and the dynamic-config subscription client.
|
|
104
|
+
|
|
105
|
+
## `deleteKeysWithPrefix(client, pattern)`
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
deleteKeysWithPrefix(client: GlideClient, pattern: string): Promise<void>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Scans keys matching `pattern` and unlinks them in batches. This helper is used by cache and rate-limiter invalidation APIs.
|
package/docs/dynamic-config.md
CHANGED
|
@@ -11,3 +11,135 @@ Fields are declared with `fieldTypes` and initialized from `defaultFields`. Miss
|
|
|
11
11
|
Use `setField()` or `setFields()` to update values. Updates are written with a Lua script that performs `HSET` and `PUBLISH` in one roundtrip.
|
|
12
12
|
|
|
13
13
|
Each instance subscribes to `dynamic-config:*` and applies matching field updates from pub/sub. Call `close()` in tests and shutdown paths to remove handlers and clear refresh timers.
|
|
14
|
+
|
|
15
|
+
## Import
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { DynamicConfig } from "valkyries";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
or:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { DynamicConfig } from "valkyries/dynamic-config";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Constructor
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
const flags = new DynamicConfig({
|
|
31
|
+
key: "feature-flags",
|
|
32
|
+
fieldTypes: { enabled: "boolean", sampleRate: "number" },
|
|
33
|
+
defaultFields: { enabled: false, sampleRate: 0 },
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
type DynamicConfigOptions = {
|
|
39
|
+
staleTtlSeconds?: number | null;
|
|
40
|
+
key: string;
|
|
41
|
+
fieldTypes: Record<string, "string" | "number" | "boolean">;
|
|
42
|
+
defaultFields: Record<string, string | number | boolean>;
|
|
43
|
+
client?: GlideClient;
|
|
44
|
+
};
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- `staleTtlSeconds`: refresh interval for local fields. Defaults to `60`.
|
|
48
|
+
- `key`: logical config name. The hash key is `dynamic-config:${key}`.
|
|
49
|
+
- `fieldTypes`: allowed fields and primitive types.
|
|
50
|
+
- `defaultFields`: default values written when fields are missing.
|
|
51
|
+
- `client`: optional `@valkey/valkey-glide` client. Defaults to the package dynamic-config client.
|
|
52
|
+
|
|
53
|
+
The constructor starts initialization immediately. Call `waitForInitialization()` before reading fields during startup.
|
|
54
|
+
|
|
55
|
+
Outside `NODE_ENV=test`, constructing multiple `DynamicConfig` instances with the same key throws.
|
|
56
|
+
|
|
57
|
+
## Public Properties
|
|
58
|
+
|
|
59
|
+
- `staleTtl`: refresh interval in seconds.
|
|
60
|
+
- `key`: Valkey hash key.
|
|
61
|
+
- `fields`: local field map.
|
|
62
|
+
- `fieldTypes`: field schema.
|
|
63
|
+
- `defaultFields`: default values.
|
|
64
|
+
- `initialization`: initialization promise.
|
|
65
|
+
|
|
66
|
+
## `waitForInitialization()`
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
config.waitForInitialization(): Promise<void>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Waits for field validation, default writes, initial field loading, pub/sub subscription, and timer creation.
|
|
73
|
+
|
|
74
|
+
## `getFields()`
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
config.getFields(): Record<string, string | number | boolean>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Returns a plain object snapshot of local fields.
|
|
81
|
+
|
|
82
|
+
## `setField(name, value)`
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
config.setField(name: string, value: string | number | boolean): Promise<void>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Writes one field and publishes the update atomically. Throws for unknown fields or invalid values for the field type.
|
|
89
|
+
|
|
90
|
+
## `setFields(fields)`
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
config.setFields(fields: Record<string, string | number | boolean>): Promise<void>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Writes multiple fields and publishes updates atomically. Local state is updated only after the Valkey write succeeds.
|
|
97
|
+
|
|
98
|
+
## `refresh()`
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
config.refresh(): Promise<void>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Refreshes local fields from Valkey when the stale TTL has elapsed. Concurrent refreshes are coalesced by an optimistic timestamp update.
|
|
105
|
+
|
|
106
|
+
## `subscribe()`
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
config.subscribe(): Promise<void>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Ensures the shared dynamic-config subscription client exists and registers this config's message handler.
|
|
113
|
+
|
|
114
|
+
## `unsubscribe()`
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
config.unsubscribe(): void
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Removes this config's message handler from the shared pub/sub dispatcher.
|
|
121
|
+
|
|
122
|
+
## `close()`
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
config.close(): Promise<void>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Marks the config closed, unsubscribes, clears the refresh timer, and removes it from the global dynamic config registry.
|
|
129
|
+
|
|
130
|
+
## `stringifyField` and `parseField`
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
config.stringifyField(type, value): string;
|
|
134
|
+
config.parseField(type, value): string | number | boolean;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Helpers used internally for Valkey storage and pub/sub messages.
|
|
138
|
+
|
|
139
|
+
## `dynamicConfigs`
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { dynamicConfigs } from "valkyries";
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Array of live `DynamicConfig` instances. It is used by `closeValkeyClients()` to close configs during shutdown.
|
|
@@ -13,3 +13,102 @@ setValkeyErrorHandler((error) => {
|
|
|
13
13
|
logger.error(error);
|
|
14
14
|
});
|
|
15
15
|
```
|
|
16
|
+
|
|
17
|
+
## `valkeyEvents`
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { valkeyEvents } from "valkyries";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`valkeyEvents` is a typed `EventEmitter`.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
valkeyEvents.on("cache:call", (event) => {
|
|
29
|
+
metrics.histogram("cache.call.duration", event.durationMs, {
|
|
30
|
+
cache: event.cacheName,
|
|
31
|
+
batch: String(event.batch),
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## `emitValkeyEvent(event, payload)`
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
emitValkeyEvent<K extends keyof ValkeyEventMap>(
|
|
40
|
+
event: K,
|
|
41
|
+
...args: ValkeyEventMap[K]
|
|
42
|
+
): void
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Emits an event and routes listener errors to the configured Valkey error handler.
|
|
46
|
+
|
|
47
|
+
## Event Payloads
|
|
48
|
+
|
|
49
|
+
Cache events:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
"cache:call": [{
|
|
53
|
+
cacheName: string;
|
|
54
|
+
batch: boolean;
|
|
55
|
+
hits: number;
|
|
56
|
+
misses: number;
|
|
57
|
+
bloomMisses: number;
|
|
58
|
+
durationMs: number;
|
|
59
|
+
}];
|
|
60
|
+
"cache:hit": [{ cacheName: string; keys: string[]; count: number }];
|
|
61
|
+
"cache:miss": [{ cacheName: string; keys: string[]; count: number }];
|
|
62
|
+
"cache:bloom-miss": [{ cacheName: string; keys: string[]; count: number }];
|
|
63
|
+
"cache:set": [{ cacheName: string; keys: string[] }];
|
|
64
|
+
"cache:set-skipped": [{ cacheName: string; keys: string[] }];
|
|
65
|
+
"cache:delete": [{ cacheName: string; keys: string[] }];
|
|
66
|
+
"cache:invalidate": [{ cacheName: string }];
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Bloom filter events:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
"bloom-filter:exists": [{ name: string; item: string; result: boolean | null }];
|
|
73
|
+
"bloom-filter:mexists": [{
|
|
74
|
+
name: string;
|
|
75
|
+
items: string[];
|
|
76
|
+
results: Array<boolean | null>;
|
|
77
|
+
}];
|
|
78
|
+
"bloom-filter:add": [{ name: string; items: string[] }];
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Rate limiter events:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
"rate-limiter:add": [{ prefix: string; ids: string[] }];
|
|
85
|
+
"rate-limiter:get": [{ prefix: string; ids: string[]; counts: number[] }];
|
|
86
|
+
"rate-limiter:delete": [{ prefix: string; ids: string[] }];
|
|
87
|
+
"rate-limiter:invalidate": [{ prefix: string }];
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## `trackCacheCall(metric)`
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
trackCacheCall(metric: {
|
|
94
|
+
cacheName: string;
|
|
95
|
+
batch: boolean;
|
|
96
|
+
hits: number;
|
|
97
|
+
misses: number;
|
|
98
|
+
bloomMisses: number;
|
|
99
|
+
duration: number;
|
|
100
|
+
}): void
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Emits `cache:call` with `duration` renamed to `durationMs`.
|
|
104
|
+
|
|
105
|
+
## Error Handling
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
setValkeyErrorHandler(handler: (error: Error) => void): void
|
|
109
|
+
handleValkeyError(error: unknown): void
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`setValkeyErrorHandler()` installs the process-wide handler used for asynchronous write failures, event listener failures, background refresh failures, and other non-fatal Valkey errors.
|
|
113
|
+
|
|
114
|
+
`handleValkeyError()` normalizes any thrown value to an `Error` and passes it to the configured handler.
|
package/docs/lua-scripts.md
CHANGED
|
@@ -5,3 +5,48 @@ Lua scripts live in `scripts/` and are copied to `dist/scripts/` during build.
|
|
|
5
5
|
Use `loadScript()` and `registerScript()` for package scripts. Registered scripts are released on process exit.
|
|
6
6
|
|
|
7
7
|
Scripts are used when operations must be atomic or when combining multiple Valkey commands into one roundtrip.
|
|
8
|
+
|
|
9
|
+
## `loadScript(relativePath, baseUrl)`
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
loadScript(relativePath: string, baseUrl: string | URL): string
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Loads a Lua script from `scripts/` relative to `baseUrl`.
|
|
16
|
+
|
|
17
|
+
## `registerScript(code)`
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
registerScript(code: string): Script
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Creates a Glide `Script`, registers it for process-exit release, and returns it.
|
|
24
|
+
|
|
25
|
+
## Packaged Scripts
|
|
26
|
+
|
|
27
|
+
Cache scripts:
|
|
28
|
+
|
|
29
|
+
- `cache-delete-with-invalidation.lua`
|
|
30
|
+
- `cache-set-if-not-invalidated.lua`
|
|
31
|
+
- `get-value-with-ttl.lua`
|
|
32
|
+
- `get-values-with-ttl.lua`
|
|
33
|
+
|
|
34
|
+
Bloom filter scripts:
|
|
35
|
+
|
|
36
|
+
- `bloom-filter-add.lua`
|
|
37
|
+
- `bloom-filter-ensure-exists.lua`
|
|
38
|
+
- `bloom-filter-exists.lua`
|
|
39
|
+
- `bloom-filter-exists-if-ready.lua`
|
|
40
|
+
- `bloom-filter-mexists.lua`
|
|
41
|
+
- `bloom-filter-mexists-if-ready.lua`
|
|
42
|
+
- `bloom-filter-reserve.lua`
|
|
43
|
+
|
|
44
|
+
Dynamic config scripts:
|
|
45
|
+
|
|
46
|
+
- `dynamic-config-set-fields.lua`
|
|
47
|
+
|
|
48
|
+
Rate limiter scripts:
|
|
49
|
+
|
|
50
|
+
- `rate-limiter-add.lua`
|
|
51
|
+
- `rate-limiter-add-and-check.lua`
|
|
52
|
+
- `rate-limiter-get.lua`
|