Skip to content

Commit 9dfc662

Browse files
committed
feat: add serialization
1 parent 35010f8 commit 9dfc662

File tree

4 files changed

+11189
-26
lines changed

4 files changed

+11189
-26
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
package-lock.json
2-
yarn.lock
32
dist/
43
node_modules/
54
**/*.tsbuildinfo

packages/store/node-server-sdk-redis/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@codefresh-io/launchdarkly-node-server-sdk-redis",
3-
"version": "3.0.11-codefresh.1",
3+
"version": "3.0.11-codefresh.2",
44
"description": "Redis-backed feature store for the LaunchDarkly Server-Side SDK for Node.js",
55
"homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/store/node-server-sdk-redis",
66
"repository": {
@@ -11,7 +11,8 @@
1111
"main": "./dist/src/index.js",
1212
"types": "./dist/src/index.d.ts",
1313
"files": [
14-
"dist"
14+
"dist",
15+
"yarn.lock"
1516
],
1617
"keywords": [
1718
"launchdarkly",
@@ -36,6 +37,7 @@
3637
"@launchdarkly/node-server-sdk": "8.2.4",
3738
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
3839
"@types/jest": "^29.4.0",
40+
"@types/redis-errors": "^1.2.3",
3941
"@typescript-eslint/eslint-plugin": "^6.1.0",
4042
"@typescript-eslint/parser": "^6.1.0",
4143
"eslint": "^8.45.0",

packages/store/node-server-sdk-redis/src/RedisCore.ts

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { MaxRetriesPerRequestError } from 'ioredis/built/errors';
2+
13
import { interfaces, LDLogger } from '@launchdarkly/node-server-sdk';
24

35
import RedisClientState from './RedisClientState';
@@ -100,6 +102,50 @@ export default class RedisCore implements interfaces.PersistentDataStore {
100102
});
101103
}
102104

105+
#serializeItems(kind: any, itemsObj: Record<string, any>) {
106+
const serializedItemsObj: Record<string, any> = {};
107+
Object.keys(itemsObj).forEach((key) => {
108+
const value = itemsObj[key];
109+
serializedItemsObj[key] = kind.serialize(value).serializedItem;
110+
});
111+
return serializedItemsObj;
112+
}
113+
114+
#prepareArray(values: Record<string, string>) {
115+
const results: interfaces.KeyedItem<string, interfaces.SerializedItemDescriptor>[] = [];
116+
Object.keys(values).forEach((key) => {
117+
const value = values[key];
118+
// When getting we do not populate version and deleted.
119+
// The SDK will have to deserialize to access these values.
120+
results.push({ key, item: { version: 0, deleted: false, serializedItem: value } });
121+
});
122+
return results;
123+
}
124+
125+
#useItemsFromCodefresh(
126+
kind: interfaces.PersistentStoreDataKind,
127+
callback: (
128+
descriptors: interfaces.KeyedItem<string, interfaces.SerializedItemDescriptor>[] | undefined,
129+
) => void,
130+
) {
131+
this.localFeatureStore().then(
132+
(items: any) => {
133+
let localResults;
134+
if (kind.namespace === 'features') {
135+
localResults = items.features;
136+
} else {
137+
localResults = items.segments;
138+
}
139+
const serializedItems = this.#serializeItems(kind, localResults);
140+
callback(this.#prepareArray(serializedItems));
141+
},
142+
(error: any) => {
143+
console.log(error);
144+
callback(undefined);
145+
},
146+
);
147+
}
148+
103149
getAll(
104150
kind: interfaces.PersistentStoreDataKind,
105151
callback: (
@@ -108,35 +154,17 @@ export default class RedisCore implements interfaces.PersistentDataStore {
108154
): void {
109155
if (!this.state.isConnected() && !this.state.isInitialConnection()) {
110156
this.logger?.warn('Attempted to fetch all keys while Redis connection is down');
111-
this.localFeatureStore().then(
112-
(items: any) => {
113-
let localResults = {};
114-
if (kind.namespace === 'features') {
115-
localResults = items.features;
116-
} else {
117-
localResults = items.segments;
118-
}
119-
callback(localResults as any);
120-
},
121-
(err: any) => {
122-
console.log(err);
123-
callback(undefined);
124-
},
125-
);
157+
this.#useItemsFromCodefresh(kind, callback);
126158
}
127159

128160
this.state.getClient().hgetall(this.state.prefixedKey(kind.namespace), (err, values) => {
129161
if (err) {
130162
this.logger?.error(`Error fetching '${kind.namespace}' from Redis ${err}`);
163+
if (err instanceof MaxRetriesPerRequestError) {
164+
this.#useItemsFromCodefresh(kind, callback);
165+
}
131166
} else if (values) {
132-
const results: interfaces.KeyedItem<string, interfaces.SerializedItemDescriptor>[] = [];
133-
Object.keys(values).forEach((key) => {
134-
const value = values[key];
135-
// When getting we do not populate version and deleted.
136-
// The SDK will have to deserialize to access these values.
137-
results.push({ key, item: { version: 0, deleted: false, serializedItem: value } });
138-
});
139-
callback(results);
167+
callback(this.#prepareArray(values));
140168
} else {
141169
callback(undefined);
142170
}

0 commit comments

Comments
 (0)