@splitsoftware/splitio-commons 1.11.0 → 1.12.0-rc.0
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/CHANGES.txt +15 -9
- package/cjs/evaluator/index.js +19 -3
- package/cjs/logger/constants.js +6 -4
- package/cjs/logger/messages/warn.js +5 -3
- package/cjs/sdkClient/client.js +19 -16
- package/cjs/sdkClient/clientInputValidation.js +16 -16
- package/cjs/sdkFactory/index.js +1 -1
- package/cjs/sdkManager/index.js +14 -13
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +3 -10
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +2 -10
- package/cjs/storages/inRedis/RedisAdapter.js +32 -13
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +2 -2
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +39 -22
- package/cjs/storages/inRedis/index.js +1 -1
- package/cjs/storages/pluggable/SplitsCachePluggable.js +28 -11
- package/cjs/storages/pluggable/index.js +1 -1
- package/cjs/utils/constants/index.js +16 -2
- package/cjs/utils/inputValidation/index.js +5 -5
- package/cjs/utils/inputValidation/{splitExistance.js → splitExistence.js} +3 -3
- package/cjs/utils/inputValidation/{trafficTypeExistance.js → trafficTypeExistence.js} +6 -6
- package/cjs/utils/lang/sets.js +11 -1
- package/cjs/utils/settingsValidation/index.js +1 -1
- package/cjs/utils/settingsValidation/splitFilters.js +25 -17
- package/esm/evaluator/index.js +20 -4
- package/esm/logger/constants.js +4 -2
- package/esm/logger/messages/warn.js +5 -3
- package/esm/sdkClient/client.js +20 -17
- package/esm/sdkClient/clientInputValidation.js +18 -18
- package/esm/sdkFactory/index.js +1 -1
- package/esm/sdkManager/index.js +11 -10
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +4 -11
- package/esm/storages/inMemory/SplitsCacheInMemory.js +3 -11
- package/esm/storages/inRedis/RedisAdapter.js +32 -13
- package/esm/storages/inRedis/SegmentsCacheInRedis.js +2 -2
- package/esm/storages/inRedis/SplitsCacheInRedis.js +40 -23
- package/esm/storages/inRedis/index.js +1 -1
- package/esm/storages/pluggable/SplitsCachePluggable.js +29 -12
- package/esm/storages/pluggable/index.js +1 -1
- package/esm/utils/constants/index.js +14 -0
- package/esm/utils/inputValidation/index.js +2 -2
- package/esm/utils/inputValidation/{splitExistance.js → splitExistence.js} +1 -1
- package/esm/utils/inputValidation/{trafficTypeExistance.js → trafficTypeExistence.js} +4 -4
- package/esm/utils/lang/sets.js +9 -0
- package/esm/utils/settingsValidation/index.js +1 -1
- package/esm/utils/settingsValidation/splitFilters.js +17 -9
- package/package.json +1 -1
- package/src/evaluator/index.ts +24 -4
- package/src/logger/constants.ts +4 -2
- package/src/logger/messages/warn.ts +9 -7
- package/src/sdkClient/client.ts +18 -18
- package/src/sdkClient/clientInputValidation.ts +18 -18
- package/src/sdkFactory/index.ts +1 -1
- package/src/sdkFactory/types.ts +3 -7
- package/src/sdkManager/index.ts +14 -14
- package/src/storages/AbstractSplitsCacheAsync.ts +1 -1
- package/src/storages/AbstractSplitsCacheSync.ts +1 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +8 -15
- package/src/storages/inMemory/SplitsCacheInMemory.ts +6 -14
- package/src/storages/inRedis/EventsCacheInRedis.ts +3 -3
- package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +3 -3
- package/src/storages/inRedis/ImpressionsCacheInRedis.ts +3 -3
- package/src/storages/inRedis/RedisAdapter.ts +38 -16
- package/src/storages/inRedis/SegmentsCacheInRedis.ts +5 -5
- package/src/storages/inRedis/SplitsCacheInRedis.ts +49 -28
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +2 -2
- package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +3 -3
- package/src/storages/inRedis/index.ts +1 -1
- package/src/storages/pluggable/SplitsCachePluggable.ts +35 -13
- package/src/storages/pluggable/index.ts +1 -1
- package/src/storages/types.ts +5 -5
- package/src/trackers/impressionObserver/utils.ts +1 -1
- package/src/types.ts +0 -2
- package/src/utils/constants/index.ts +16 -0
- package/src/utils/inputValidation/index.ts +2 -2
- package/src/utils/inputValidation/{splitExistance.ts → splitExistence.ts} +1 -1
- package/src/utils/inputValidation/{trafficTypeExistance.ts → trafficTypeExistence.ts} +4 -4
- package/src/utils/lang/sets.ts +9 -1
- package/src/utils/redis/RedisMock.ts +1 -3
- package/src/utils/settingsValidation/index.ts +1 -1
- package/src/utils/settingsValidation/splitFilters.ts +19 -11
- package/types/evaluator/index.d.ts +1 -1
- package/types/logger/constants.d.ts +4 -2
- package/types/sdkClient/identity.d.ts +6 -0
- package/types/sdkFactory/types.d.ts +3 -3
- package/types/sdkManager/index.d.ts +2 -3
- package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
- package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -1
- package/types/storages/inRedis/EventsCacheInRedis.d.ts +2 -2
- package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +3 -2
- package/types/storages/inRedis/ImpressionsCacheInRedis.d.ts +2 -2
- package/types/storages/inRedis/RedisAdapter.d.ts +1 -1
- package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +3 -3
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +10 -14
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +2 -2
- package/types/storages/inRedis/{uniqueKeysCacheInRedis.d.ts → UniqueKeysCacheInRedis.d.ts} +3 -2
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +10 -9
- package/types/storages/types.d.ts +5 -5
- package/types/trackers/impressionObserver/utils.d.ts +1 -1
- package/types/types.d.ts +0 -2
- package/types/utils/constants/index.d.ts +12 -0
- package/types/utils/inputValidation/index.d.ts +2 -2
- package/types/utils/inputValidation/sdkKey.d.ts +7 -0
- package/types/utils/inputValidation/splitExistence.d.ts +7 -0
- package/types/utils/inputValidation/trafficTypeExistence.d.ts +9 -0
- package/types/utils/lang/sets.d.ts +1 -0
- package/types/utils/settingsValidation/splitFilters.d.ts +3 -2
- package/types/myLogger.d.ts +0 -5
- package/types/sdkClient/types.d.ts +0 -18
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
- package/types/storages/metadataBuilder.d.ts +0 -3
- package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
- package/types/sync/offline/updaters/splitChangesUpdater.d.ts +0 -0
- package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
- package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +0 -5
- package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
- package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
- package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
- package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
- package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +0 -5
- package/types/sync/syncTaskComposite.d.ts +0 -5
- package/types/trackers/filter/bloomFilter.d.ts +0 -10
- package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
- package/types/trackers/filter/types.d.ts +0 -5
- package/types/utils/timeTracker/index.d.ts +0 -70
- /package/types/storages/inMemory/{uniqueKeysCacheInMemory.d.ts → UniqueKeysCacheInMemory.d.ts} +0 -0
- /package/types/storages/inMemory/{uniqueKeysCacheInMemoryCS.d.ts → UniqueKeysCacheInMemoryCS.d.ts} +0 -0
package/esm/sdkClient/client.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { evaluateFeature, evaluateFeatures, evaluateFeaturesByFlagSets } from '../evaluator';
|
|
2
2
|
import { thenable } from '../utils/promise/thenable';
|
|
3
3
|
import { getMatching, getBucketing } from '../utils/key';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { validateSplitExistence } from '../utils/inputValidation/splitExistence';
|
|
5
|
+
import { validateTrafficTypeExistence } from '../utils/inputValidation/trafficTypeExistence';
|
|
6
6
|
import { SDK_NOT_READY } from '../utils/labels';
|
|
7
|
-
import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TRACK, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, TREATMENTS_BY_FLAGSETS, TREATMENTS_BY_FLAGSET, TREATMENTS_WITH_CONFIG_BY_FLAGSET } from '../utils/constants';
|
|
7
|
+
import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TRACK, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, TREATMENTS_BY_FLAGSETS, TREATMENTS_BY_FLAGSET, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENT_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, TRACK_FN_LABEL } from '../utils/constants';
|
|
8
8
|
import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
|
|
9
9
|
import { isStorageSync } from '../trackers/impressionObserver/utils';
|
|
10
10
|
var treatmentNotReady = { treatment: CONTROL, label: SDK_NOT_READY };
|
|
@@ -21,12 +21,13 @@ function treatmentsNotReady(featureFlagNames) {
|
|
|
21
21
|
export function clientFactory(params) {
|
|
22
22
|
var readinessManager = params.sdkReadinessManager.readinessManager, storage = params.storage, settings = params.settings, impressionsTracker = params.impressionsTracker, eventTracker = params.eventTracker, telemetryTracker = params.telemetryTracker;
|
|
23
23
|
var log = settings.log, mode = settings.mode;
|
|
24
|
-
function getTreatment(key, featureFlagName, attributes, withConfig) {
|
|
24
|
+
function getTreatment(key, featureFlagName, attributes, withConfig, methodName) {
|
|
25
25
|
if (withConfig === void 0) { withConfig = false; }
|
|
26
|
+
if (methodName === void 0) { methodName = GET_TREATMENT; }
|
|
26
27
|
var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
|
|
27
28
|
var wrapUp = function (evaluationResult) {
|
|
28
29
|
var queue = [];
|
|
29
|
-
var treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig,
|
|
30
|
+
var treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
30
31
|
impressionsTracker.track(queue, attributes);
|
|
31
32
|
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
32
33
|
return treatment;
|
|
@@ -39,16 +40,17 @@ export function clientFactory(params) {
|
|
|
39
40
|
return thenable(evaluation) ? evaluation.then(function (res) { return wrapUp(res); }) : wrapUp(evaluation);
|
|
40
41
|
}
|
|
41
42
|
function getTreatmentWithConfig(key, featureFlagName, attributes) {
|
|
42
|
-
return getTreatment(key, featureFlagName, attributes, true);
|
|
43
|
+
return getTreatment(key, featureFlagName, attributes, true, GET_TREATMENT_WITH_CONFIG);
|
|
43
44
|
}
|
|
44
|
-
function getTreatments(key, featureFlagNames, attributes, withConfig) {
|
|
45
|
+
function getTreatments(key, featureFlagNames, attributes, withConfig, methodName) {
|
|
45
46
|
if (withConfig === void 0) { withConfig = false; }
|
|
47
|
+
if (methodName === void 0) { methodName = GET_TREATMENTS; }
|
|
46
48
|
var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
|
|
47
49
|
var wrapUp = function (evaluationResults) {
|
|
48
50
|
var queue = [];
|
|
49
51
|
var treatments = {};
|
|
50
52
|
Object.keys(evaluationResults).forEach(function (featureFlagName) {
|
|
51
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig,
|
|
53
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
52
54
|
});
|
|
53
55
|
impressionsTracker.track(queue, attributes);
|
|
54
56
|
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
@@ -62,36 +64,37 @@ export function clientFactory(params) {
|
|
|
62
64
|
return thenable(evaluations) ? evaluations.then(function (res) { return wrapUp(res); }) : wrapUp(evaluations);
|
|
63
65
|
}
|
|
64
66
|
function getTreatmentsWithConfig(key, featureFlagNames, attributes) {
|
|
65
|
-
return getTreatments(key, featureFlagNames, attributes, true);
|
|
67
|
+
return getTreatments(key, featureFlagNames, attributes, true, GET_TREATMENTS_WITH_CONFIG);
|
|
66
68
|
}
|
|
67
|
-
function getTreatmentsByFlagSets(key, flagSetNames, attributes, withConfig, method) {
|
|
69
|
+
function getTreatmentsByFlagSets(key, flagSetNames, attributes, withConfig, method, methodName) {
|
|
68
70
|
if (withConfig === void 0) { withConfig = false; }
|
|
69
71
|
if (method === void 0) { method = TREATMENTS_BY_FLAGSETS; }
|
|
72
|
+
if (methodName === void 0) { methodName = GET_TREATMENTS_BY_FLAG_SETS; }
|
|
70
73
|
var stopTelemetryTracker = telemetryTracker.trackEval(method);
|
|
71
74
|
var wrapUp = function (evaluationResults) {
|
|
72
75
|
var queue = [];
|
|
73
76
|
var treatments = {};
|
|
74
77
|
var evaluations = evaluationResults;
|
|
75
78
|
Object.keys(evaluations).forEach(function (featureFlagName) {
|
|
76
|
-
treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig,
|
|
79
|
+
treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
77
80
|
});
|
|
78
81
|
impressionsTracker.track(queue, attributes);
|
|
79
82
|
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
80
83
|
return treatments;
|
|
81
84
|
};
|
|
82
85
|
var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
|
|
83
|
-
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage) :
|
|
86
|
+
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName) :
|
|
84
87
|
isStorageSync(settings) ? {} : Promise.resolve({}); // Promisify if async
|
|
85
88
|
return thenable(evaluations) ? evaluations.then(function (res) { return wrapUp(res); }) : wrapUp(evaluations);
|
|
86
89
|
}
|
|
87
90
|
function getTreatmentsWithConfigByFlagSets(key, flagSetNames, attributes) {
|
|
88
|
-
return getTreatmentsByFlagSets(key, flagSetNames, attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS);
|
|
91
|
+
return getTreatmentsByFlagSets(key, flagSetNames, attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
|
|
89
92
|
}
|
|
90
93
|
function getTreatmentsByFlagSet(key, flagSetName, attributes) {
|
|
91
|
-
return getTreatmentsByFlagSets(key, [flagSetName], attributes, false, TREATMENTS_BY_FLAGSET);
|
|
94
|
+
return getTreatmentsByFlagSets(key, [flagSetName], attributes, false, TREATMENTS_BY_FLAGSET, GET_TREATMENTS_BY_FLAG_SET);
|
|
92
95
|
}
|
|
93
96
|
function getTreatmentsWithConfigByFlagSet(key, flagSetName, attributes) {
|
|
94
|
-
return getTreatmentsByFlagSets(key, [flagSetName], attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET);
|
|
97
|
+
return getTreatmentsByFlagSets(key, [flagSetName], attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
|
|
95
98
|
}
|
|
96
99
|
// Internal function
|
|
97
100
|
function processEvaluation(evaluation, featureFlagName, key, attributes, withConfig, invokingMethodName, queue) {
|
|
@@ -99,7 +102,7 @@ export function clientFactory(params) {
|
|
|
99
102
|
var bucketingKey = getBucketing(key);
|
|
100
103
|
var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a;
|
|
101
104
|
log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
|
|
102
|
-
if (
|
|
105
|
+
if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
|
|
103
106
|
log.info(IMPRESSION_QUEUEING);
|
|
104
107
|
queue.push({
|
|
105
108
|
feature: featureFlagName,
|
|
@@ -133,7 +136,7 @@ export function clientFactory(params) {
|
|
|
133
136
|
properties: properties
|
|
134
137
|
};
|
|
135
138
|
// This may be async but we only warn, we don't actually care if it is valid or not in terms of queueing the event.
|
|
136
|
-
|
|
139
|
+
validateTrafficTypeExistence(log, readinessManager, storage.splits, mode, trafficTypeName, TRACK_FN_LABEL);
|
|
137
140
|
var result = eventTracker.track(eventData, size);
|
|
138
141
|
if (thenable(result)) {
|
|
139
142
|
return result.then(function (result) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfOperational } from '../utils/inputValidation';
|
|
3
3
|
import { startsWith } from '../utils/lang';
|
|
4
|
-
import { CONTROL, CONTROL_WITH_CONFIG } from '../utils/constants';
|
|
4
|
+
import { CONTROL, CONTROL_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENT_WITH_CONFIG, TRACK_FN_LABEL } from '../utils/constants';
|
|
5
5
|
import { isStorageSync } from '../trackers/impressionObserver/utils';
|
|
6
|
-
import {
|
|
6
|
+
import { validateFlagSets } from '../utils/settingsValidation/splitFilters';
|
|
7
7
|
/**
|
|
8
8
|
* Decorator that validates the input before actually executing the client methods.
|
|
9
9
|
* We should "guard" the client here, while not polluting the "real" implementation of those methods.
|
|
@@ -15,7 +15,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
15
15
|
* Avoid repeating this validations code
|
|
16
16
|
*/
|
|
17
17
|
function validateEvaluationParams(maybeKey, maybeFeatureFlagNameOrNames, maybeAttributes, methodName, maybeFlagSetNameOrNames) {
|
|
18
|
-
var multi = startsWith(methodName,
|
|
18
|
+
var multi = startsWith(methodName, GET_TREATMENTS);
|
|
19
19
|
var key = validateKey(log, maybeKey, methodName);
|
|
20
20
|
var splitOrSplits = false;
|
|
21
21
|
var flagSetOrFlagSets = [];
|
|
@@ -25,7 +25,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
25
25
|
var attributes = validateAttributes(log, maybeAttributes, methodName);
|
|
26
26
|
var isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
|
|
27
27
|
if (maybeFlagSetNameOrNames) {
|
|
28
|
-
flagSetOrFlagSets =
|
|
28
|
+
flagSetOrFlagSets = validateFlagSets(log, methodName, maybeFlagSetNameOrNames, settings.sync.__splitFiltersValidation.groupedFilters.bySet);
|
|
29
29
|
}
|
|
30
30
|
validateIfOperational(log, readinessManager, methodName, splitOrSplits);
|
|
31
31
|
var valid = isNotDestroyed && key && (splitOrSplits || flagSetOrFlagSets.length > 0) && attributes !== false;
|
|
@@ -41,7 +41,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
41
41
|
return isSync ? value : Promise.resolve(value);
|
|
42
42
|
}
|
|
43
43
|
function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes) {
|
|
44
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes,
|
|
44
|
+
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes, GET_TREATMENT);
|
|
45
45
|
if (params.valid) {
|
|
46
46
|
return client.getTreatment(params.key, params.splitOrSplits, params.attributes);
|
|
47
47
|
}
|
|
@@ -50,7 +50,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes) {
|
|
53
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes,
|
|
53
|
+
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes, GET_TREATMENT_WITH_CONFIG);
|
|
54
54
|
if (params.valid) {
|
|
55
55
|
return client.getTreatmentWithConfig(params.key, params.splitOrSplits, params.attributes);
|
|
56
56
|
}
|
|
@@ -59,7 +59,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
|
|
62
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes,
|
|
62
|
+
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes, GET_TREATMENTS);
|
|
63
63
|
if (params.valid) {
|
|
64
64
|
return client.getTreatments(params.key, params.splitOrSplits, params.attributes);
|
|
65
65
|
}
|
|
@@ -71,7 +71,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
|
|
74
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes,
|
|
74
|
+
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes, GET_TREATMENTS_WITH_CONFIG);
|
|
75
75
|
if (params.valid) {
|
|
76
76
|
return client.getTreatmentsWithConfig(params.key, params.splitOrSplits, params.attributes);
|
|
77
77
|
}
|
|
@@ -83,7 +83,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
86
|
-
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes,
|
|
86
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, GET_TREATMENTS_BY_FLAG_SETS, maybeFlagSets);
|
|
87
87
|
if (params.valid) {
|
|
88
88
|
return client.getTreatmentsByFlagSets(params.key, params.flagSetOrFlagSets, params.attributes);
|
|
89
89
|
}
|
|
@@ -92,7 +92,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
95
|
-
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes,
|
|
95
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, maybeFlagSets);
|
|
96
96
|
if (params.valid) {
|
|
97
97
|
return client.getTreatmentsWithConfigByFlagSets(params.key, params.flagSetOrFlagSets, params.attributes);
|
|
98
98
|
}
|
|
@@ -101,7 +101,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
104
|
-
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes,
|
|
104
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, GET_TREATMENTS_BY_FLAG_SET, [maybeFlagSet]);
|
|
105
105
|
if (params.valid) {
|
|
106
106
|
return client.getTreatmentsByFlagSet(params.key, params.flagSetOrFlagSets[0], params.attributes);
|
|
107
107
|
}
|
|
@@ -110,7 +110,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
113
|
-
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes,
|
|
113
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, [maybeFlagSet]);
|
|
114
114
|
if (params.valid) {
|
|
115
115
|
return client.getTreatmentsWithConfigByFlagSet(params.key, params.flagSetOrFlagSets[0], params.attributes);
|
|
116
116
|
}
|
|
@@ -119,12 +119,12 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
function track(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties) {
|
|
122
|
-
var key = validateKey(log, maybeKey,
|
|
123
|
-
var tt = validateTrafficType(log, maybeTT,
|
|
124
|
-
var event = validateEvent(log, maybeEvent,
|
|
125
|
-
var eventValue = validateEventValue(log, maybeEventValue,
|
|
126
|
-
var _a = validateEventProperties(log, maybeProperties,
|
|
127
|
-
var isNotDestroyed = validateIfNotDestroyed(log, readinessManager,
|
|
122
|
+
var key = validateKey(log, maybeKey, TRACK_FN_LABEL);
|
|
123
|
+
var tt = validateTrafficType(log, maybeTT, TRACK_FN_LABEL);
|
|
124
|
+
var event = validateEvent(log, maybeEvent, TRACK_FN_LABEL);
|
|
125
|
+
var eventValue = validateEventValue(log, maybeEventValue, TRACK_FN_LABEL);
|
|
126
|
+
var _a = validateEventProperties(log, maybeProperties, TRACK_FN_LABEL), properties = _a.properties, size = _a.size;
|
|
127
|
+
var isNotDestroyed = validateIfNotDestroyed(log, readinessManager, TRACK_FN_LABEL);
|
|
128
128
|
if (isNotDestroyed && key && tt && event && eventValue !== false && properties !== false) { // @ts-expect-error
|
|
129
129
|
return client.track(key, tt, event, eventValue, properties, size);
|
|
130
130
|
}
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -63,7 +63,7 @@ export function sdkFactory(params) {
|
|
|
63
63
|
ctx.signalListener = signalListener;
|
|
64
64
|
// SDK client and manager
|
|
65
65
|
var clientMethod = sdkClientMethodFactory(ctx);
|
|
66
|
-
var managerInstance = sdkManagerFactory(
|
|
66
|
+
var managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
|
|
67
67
|
syncManager && syncManager.start();
|
|
68
68
|
signalListener && signalListener.start();
|
|
69
69
|
log.info(NEW_FACTORY);
|
package/esm/sdkManager/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { thenable } from '../utils/promise/thenable';
|
|
3
3
|
import { find } from '../utils/lang';
|
|
4
|
-
import { validateSplit,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var NAMES_FN_LABEL = 'names';
|
|
4
|
+
import { validateSplit, validateSplitExistence, validateIfNotDestroyed, validateIfOperational } from '../utils/inputValidation';
|
|
5
|
+
import { isStorageSync } from '../trackers/impressionObserver/utils';
|
|
6
|
+
import { SPLIT_FN_LABEL, SPLITS_FN_LABEL, NAMES_FN_LABEL } from '../utils/constants';
|
|
8
7
|
function collectTreatments(splitObject) {
|
|
9
8
|
var conditions = splitObject.conditions;
|
|
10
9
|
// Rollout conditions are supposed to have the entire partitions list, so we find the first one.
|
|
@@ -38,8 +37,10 @@ function objectsToViews(splitObjects) {
|
|
|
38
37
|
});
|
|
39
38
|
return views;
|
|
40
39
|
}
|
|
41
|
-
export function sdkManagerFactory(
|
|
40
|
+
export function sdkManagerFactory(settings, splits, _a) {
|
|
42
41
|
var readinessManager = _a.readinessManager, sdkStatus = _a.sdkStatus;
|
|
42
|
+
var log = settings.log;
|
|
43
|
+
var isSync = isStorageSync(settings);
|
|
43
44
|
return objectAssign(
|
|
44
45
|
// Proto-linkage of the readiness Event Emitter
|
|
45
46
|
Object.create(sdkStatus), {
|
|
@@ -49,16 +50,16 @@ export function sdkManagerFactory(log, splits, _a) {
|
|
|
49
50
|
split: function (featureFlagName) {
|
|
50
51
|
var splitName = validateSplit(log, featureFlagName, SPLIT_FN_LABEL);
|
|
51
52
|
if (!validateIfNotDestroyed(log, readinessManager, SPLIT_FN_LABEL) || !validateIfOperational(log, readinessManager, SPLIT_FN_LABEL) || !splitName) {
|
|
52
|
-
return null;
|
|
53
|
+
return isSync ? null : Promise.resolve(null);
|
|
53
54
|
}
|
|
54
55
|
var split = splits.getSplit(splitName);
|
|
55
56
|
if (thenable(split)) {
|
|
56
57
|
return split.catch(function () { return null; }).then(function (result) {
|
|
57
|
-
|
|
58
|
+
validateSplitExistence(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
|
|
58
59
|
return objectToView(result);
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
+
validateSplitExistence(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
|
|
62
63
|
return objectToView(split);
|
|
63
64
|
},
|
|
64
65
|
/**
|
|
@@ -66,7 +67,7 @@ export function sdkManagerFactory(log, splits, _a) {
|
|
|
66
67
|
*/
|
|
67
68
|
splits: function () {
|
|
68
69
|
if (!validateIfNotDestroyed(log, readinessManager, SPLITS_FN_LABEL) || !validateIfOperational(log, readinessManager, SPLITS_FN_LABEL)) {
|
|
69
|
-
return [];
|
|
70
|
+
return isSync ? [] : Promise.resolve([]);
|
|
70
71
|
}
|
|
71
72
|
var currentSplits = splits.getAll();
|
|
72
73
|
return thenable(currentSplits) ?
|
|
@@ -78,7 +79,7 @@ export function sdkManagerFactory(log, splits, _a) {
|
|
|
78
79
|
*/
|
|
79
80
|
names: function () {
|
|
80
81
|
if (!validateIfNotDestroyed(log, readinessManager, NAMES_FN_LABEL) || !validateIfOperational(log, readinessManager, NAMES_FN_LABEL)) {
|
|
81
|
-
return [];
|
|
82
|
+
return isSync ? [] : Promise.resolve([]);
|
|
82
83
|
}
|
|
83
84
|
var splitNames = splits.getSplitNames();
|
|
84
85
|
return thenable(splitNames) ?
|
|
@@ -2,7 +2,7 @@ import { __extends } from "tslib";
|
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
|
-
import { _Set,
|
|
5
|
+
import { _Set, setToArray } from '../../utils/lang/sets';
|
|
6
6
|
/**
|
|
7
7
|
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
|
|
8
8
|
*/
|
|
@@ -228,16 +228,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
228
228
|
};
|
|
229
229
|
SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
|
|
230
230
|
var _this = this;
|
|
231
|
-
|
|
232
|
-
flagSets.forEach(function (flagSet) {
|
|
231
|
+
return flagSets.map(function (flagSet) {
|
|
233
232
|
var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
|
|
234
233
|
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
235
|
-
|
|
236
|
-
var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
237
|
-
toReturn = returnSetsUnion(toReturn, flagSetCache);
|
|
238
|
-
}
|
|
234
|
+
return new _Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
239
235
|
});
|
|
240
|
-
return toReturn;
|
|
241
236
|
};
|
|
242
237
|
SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
|
|
243
238
|
var _this = this;
|
|
@@ -248,9 +243,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
248
243
|
return;
|
|
249
244
|
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
|
|
250
245
|
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
251
|
-
|
|
252
|
-
flagSetFromLocalStorage = '[]';
|
|
253
|
-
var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
246
|
+
var flagSetCache = new _Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
254
247
|
flagSetCache.add(featureFlag.name);
|
|
255
248
|
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
256
249
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __extends } from "tslib";
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber } from '../../utils/lang';
|
|
4
|
-
import { _Set
|
|
4
|
+
import { _Set } from '../../utils/lang/sets';
|
|
5
5
|
/**
|
|
6
6
|
* Default ISplitsCacheSync implementation that stores split definitions in memory.
|
|
7
7
|
* Supported by all JS runtimes.
|
|
@@ -9,14 +9,13 @@ import { _Set, returnSetsUnion } from '../../utils/lang/sets';
|
|
|
9
9
|
var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
10
10
|
__extends(SplitsCacheInMemory, _super);
|
|
11
11
|
function SplitsCacheInMemory(splitFiltersValidation) {
|
|
12
|
-
if (splitFiltersValidation === void 0) { splitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] }; }
|
|
13
12
|
var _this = _super.call(this) || this;
|
|
14
13
|
_this.splitsCache = {};
|
|
15
14
|
_this.ttCache = {};
|
|
16
15
|
_this.changeNumber = -1;
|
|
17
16
|
_this.splitsWithSegmentsCount = 0;
|
|
18
17
|
_this.flagSetsCache = {};
|
|
19
|
-
_this.flagSetsFilter = splitFiltersValidation.groupedFilters.bySet;
|
|
18
|
+
_this.flagSetsFilter = splitFiltersValidation ? splitFiltersValidation.groupedFilters.bySet : [];
|
|
20
19
|
return _this;
|
|
21
20
|
}
|
|
22
21
|
SplitsCacheInMemory.prototype.clear = function () {
|
|
@@ -93,14 +92,7 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
93
92
|
};
|
|
94
93
|
SplitsCacheInMemory.prototype.getNamesByFlagSets = function (flagSets) {
|
|
95
94
|
var _this = this;
|
|
96
|
-
|
|
97
|
-
flagSets.forEach(function (flagSet) {
|
|
98
|
-
var featureFlagNames = _this.flagSetsCache[flagSet];
|
|
99
|
-
if (featureFlagNames) {
|
|
100
|
-
toReturn = returnSetsUnion(toReturn, featureFlagNames);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
return toReturn;
|
|
95
|
+
return flagSets.map(function (flagSet) { return _this.flagSetsCache[flagSet] || new _Set(); });
|
|
104
96
|
};
|
|
105
97
|
SplitsCacheInMemory.prototype.addToFlagSets = function (featureFlag) {
|
|
106
98
|
var _this = this;
|
|
@@ -6,7 +6,8 @@ import { thenable } from '../../utils/promise/thenable';
|
|
|
6
6
|
import { timeout } from '../../utils/promise/timeout';
|
|
7
7
|
var LOG_PREFIX = 'storage:redis-adapter: ';
|
|
8
8
|
// If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis.
|
|
9
|
-
var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', '
|
|
9
|
+
var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'expire', 'mget', 'lrange', 'ltrim', 'hset', 'hincrby', 'popNRaw'];
|
|
10
|
+
var METHODS_TO_PROMISE_WRAP_EXEC = ['pipeline'];
|
|
10
11
|
// Not part of the settings since it'll vary on each storage. We should be removing storage specific logic from elsewhere.
|
|
11
12
|
var DEFAULT_OPTIONS = {
|
|
12
13
|
connectionTimeout: 10000,
|
|
@@ -24,6 +25,7 @@ var DEFAULT_LIBRARY_OPTIONS = {
|
|
|
24
25
|
var RedisAdapter = /** @class */ (function (_super) {
|
|
25
26
|
__extends(RedisAdapter, _super);
|
|
26
27
|
function RedisAdapter(log, storageSettings) {
|
|
28
|
+
if (storageSettings === void 0) { storageSettings = {}; }
|
|
27
29
|
var _this = this;
|
|
28
30
|
var options = RedisAdapter._defineOptions(storageSettings);
|
|
29
31
|
// Call the ioredis constructor
|
|
@@ -55,14 +57,15 @@ var RedisAdapter = /** @class */ (function (_super) {
|
|
|
55
57
|
};
|
|
56
58
|
RedisAdapter.prototype._setTimeoutWrappers = function () {
|
|
57
59
|
var instance = this;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
instance
|
|
60
|
+
var wrapCommand = function (originalMethod, methodName) {
|
|
61
|
+
// The value of "this" in this function should be the instance actually executing the method. It might be the instance referred (the base one)
|
|
62
|
+
// or it can be the instance of a Pipeline object.
|
|
63
|
+
return function () {
|
|
61
64
|
var params = arguments;
|
|
65
|
+
var caller = this;
|
|
62
66
|
function commandWrapper() {
|
|
63
|
-
instance.log.debug(LOG_PREFIX +
|
|
64
|
-
|
|
65
|
-
var result = originalMethod.apply(instance, params);
|
|
67
|
+
instance.log.debug(LOG_PREFIX + "Executing " + methodName + ".");
|
|
68
|
+
var result = originalMethod.apply(caller, params);
|
|
66
69
|
if (thenable(result)) {
|
|
67
70
|
// For handling pending commands on disconnect, add to the set and remove once finished.
|
|
68
71
|
// On sync commands there's no need, only thenables.
|
|
@@ -73,7 +76,7 @@ var RedisAdapter = /** @class */ (function (_super) {
|
|
|
73
76
|
// Both success and error remove from queue.
|
|
74
77
|
result.then(cleanUpRunningCommandsCb, cleanUpRunningCommandsCb);
|
|
75
78
|
return timeout(instance._options.operationTimeout, result).catch(function (err) {
|
|
76
|
-
instance.log.error(LOG_PREFIX +
|
|
79
|
+
instance.log.error("" + LOG_PREFIX + methodName + " operation threw an error or exceeded configured timeout of " + instance._options.operationTimeout + "ms. Message: " + err);
|
|
77
80
|
// Handling is not the adapter responsibility.
|
|
78
81
|
throw err;
|
|
79
82
|
});
|
|
@@ -81,12 +84,12 @@ var RedisAdapter = /** @class */ (function (_super) {
|
|
|
81
84
|
return result;
|
|
82
85
|
}
|
|
83
86
|
if (instance._notReadyCommandsQueue) {
|
|
84
|
-
return new Promise(function (
|
|
87
|
+
return new Promise(function (resolve, reject) {
|
|
85
88
|
instance._notReadyCommandsQueue.unshift({
|
|
86
|
-
resolve:
|
|
87
|
-
reject:
|
|
89
|
+
resolve: resolve,
|
|
90
|
+
reject: reject,
|
|
88
91
|
command: commandWrapper,
|
|
89
|
-
name:
|
|
92
|
+
name: methodName.toUpperCase()
|
|
90
93
|
});
|
|
91
94
|
});
|
|
92
95
|
}
|
|
@@ -94,6 +97,22 @@ var RedisAdapter = /** @class */ (function (_super) {
|
|
|
94
97
|
return commandWrapper();
|
|
95
98
|
}
|
|
96
99
|
};
|
|
100
|
+
};
|
|
101
|
+
// Wrap regular async methods to track timeouts and queue when Redis is not yet executing commands.
|
|
102
|
+
METHODS_TO_PROMISE_WRAP.forEach(function (methodName) {
|
|
103
|
+
var originalFn = instance[methodName];
|
|
104
|
+
instance[methodName] = wrapCommand(originalFn, methodName);
|
|
105
|
+
});
|
|
106
|
+
// Special handling for pipeline~like methods. We need to wrap the async trigger, which is exec, but return the Pipeline right away.
|
|
107
|
+
METHODS_TO_PROMISE_WRAP_EXEC.forEach(function (methodName) {
|
|
108
|
+
var originalFn = instance[methodName];
|
|
109
|
+
// "First level wrapper" to handle the sync execution and wrap async, queueing later if applicable.
|
|
110
|
+
instance[methodName] = function () {
|
|
111
|
+
var res = originalFn.apply(instance, arguments);
|
|
112
|
+
var originalExec = res.exec;
|
|
113
|
+
res.exec = wrapCommand(originalExec, methodName + '.exec').bind(res);
|
|
114
|
+
return res;
|
|
115
|
+
};
|
|
97
116
|
});
|
|
98
117
|
};
|
|
99
118
|
RedisAdapter.prototype._setDisconnectWrapper = function () {
|
|
@@ -104,7 +123,7 @@ var RedisAdapter = /** @class */ (function (_super) {
|
|
|
104
123
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
105
124
|
params[_i] = arguments[_i];
|
|
106
125
|
}
|
|
107
|
-
setTimeout(function
|
|
126
|
+
setTimeout(function deferredDisconnect() {
|
|
108
127
|
if (instance._runningCommands.size > 0) {
|
|
109
128
|
instance.log.info(LOG_PREFIX + ("Attempting to disconnect but there are " + instance._runningCommands.size + " commands still waiting for resolution. Defering disconnection until those finish."));
|
|
110
129
|
Promise.all(setToArray(instance._runningCommands))
|
|
@@ -51,9 +51,9 @@ var SegmentsCacheInRedis = /** @class */ (function () {
|
|
|
51
51
|
SegmentsCacheInRedis.prototype.getRegisteredSegments = function () {
|
|
52
52
|
return this.redis.smembers(this.keys.buildRegisteredSegmentsKey());
|
|
53
53
|
};
|
|
54
|
-
// @TODO remove
|
|
54
|
+
// @TODO remove or implement. It is not being used.
|
|
55
55
|
SegmentsCacheInRedis.prototype.clear = function () {
|
|
56
|
-
return
|
|
56
|
+
return Promise.resolve();
|
|
57
57
|
};
|
|
58
58
|
return SegmentsCacheInRedis;
|
|
59
59
|
}());
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { __extends } from "tslib";
|
|
1
|
+
import { __extends, __spreadArray } from "tslib";
|
|
2
2
|
import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
3
3
|
import { LOG_PREFIX } from './constants';
|
|
4
4
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
5
|
+
import { _Set, returnDifference } from '../../utils/lang/sets';
|
|
5
6
|
/**
|
|
6
7
|
* Discard errors for an answer of multiple operations.
|
|
7
8
|
*/
|
|
@@ -18,11 +19,12 @@ function processPipelineAnswer(results) {
|
|
|
18
19
|
*/
|
|
19
20
|
var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
20
21
|
__extends(SplitsCacheInRedis, _super);
|
|
21
|
-
function SplitsCacheInRedis(log, keys, redis) {
|
|
22
|
+
function SplitsCacheInRedis(log, keys, redis, splitFiltersValidation) {
|
|
22
23
|
var _this = _super.call(this) || this;
|
|
23
24
|
_this.log = log;
|
|
24
25
|
_this.redis = redis;
|
|
25
26
|
_this.keys = keys;
|
|
27
|
+
_this.flagSetsFilter = splitFiltersValidation ? splitFiltersValidation.groupedFilters.bySet : [];
|
|
26
28
|
// There is no need to listen for redis 'error' event, because in that case ioredis calls will be rejected and handled by redis storage adapters.
|
|
27
29
|
// But it is done just to avoid getting the ioredis message `Unhandled error event`.
|
|
28
30
|
_this.redis.on('error', function (e) {
|
|
@@ -45,6 +47,18 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
45
47
|
var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
|
|
46
48
|
return this.redis.incr(ttKey);
|
|
47
49
|
};
|
|
50
|
+
SplitsCacheInRedis.prototype._updateFlagSets = function (featureFlagName, flagSetsOfRemovedFlag, flagSetsOfAddedFlag) {
|
|
51
|
+
var _this = this;
|
|
52
|
+
var removeFromFlagSets = returnDifference(flagSetsOfRemovedFlag, flagSetsOfAddedFlag);
|
|
53
|
+
var addToFlagSets = returnDifference(flagSetsOfAddedFlag, flagSetsOfRemovedFlag);
|
|
54
|
+
if (this.flagSetsFilter.length > 0) {
|
|
55
|
+
addToFlagSets = addToFlagSets.filter(function (flagSet) {
|
|
56
|
+
return _this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === flagSet; });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
var items = [featureFlagName];
|
|
60
|
+
return Promise.all(__spreadArray(__spreadArray([], removeFromFlagSets.map(function (flagSetName) { return _this.redis.srem(_this.keys.buildFlagSetKey(flagSetName), items); }), true), addToFlagSets.map(function (flagSetName) { return _this.redis.sadd(_this.keys.buildFlagSetKey(flagSetName), items); }), true));
|
|
61
|
+
};
|
|
48
62
|
/**
|
|
49
63
|
* Add a given split.
|
|
50
64
|
* The returned promise is resolved when the operation success
|
|
@@ -54,16 +68,16 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
54
68
|
var _this = this;
|
|
55
69
|
var splitKey = this.keys.buildSplitKey(name);
|
|
56
70
|
return this.redis.get(splitKey).then(function (splitFromStorage) {
|
|
57
|
-
// handling parsing
|
|
58
|
-
var parsedPreviousSplit,
|
|
71
|
+
// handling parsing error
|
|
72
|
+
var parsedPreviousSplit, stringifiedNewSplit;
|
|
59
73
|
try {
|
|
60
74
|
parsedPreviousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : undefined;
|
|
61
|
-
|
|
75
|
+
stringifiedNewSplit = JSON.stringify(split);
|
|
62
76
|
}
|
|
63
77
|
catch (e) {
|
|
64
78
|
throw new Error('Error parsing feature flag definition: ' + e);
|
|
65
79
|
}
|
|
66
|
-
return _this.redis.set(splitKey,
|
|
80
|
+
return _this.redis.set(splitKey, stringifiedNewSplit).then(function () {
|
|
67
81
|
// avoid unnecessary increment/decrement operations
|
|
68
82
|
if (parsedPreviousSplit && parsedPreviousSplit.trafficTypeName === split.trafficTypeName)
|
|
69
83
|
return;
|
|
@@ -72,7 +86,7 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
72
86
|
if (parsedPreviousSplit)
|
|
73
87
|
return _this._decrementCounts(parsedPreviousSplit);
|
|
74
88
|
});
|
|
75
|
-
});
|
|
89
|
+
}).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
|
|
76
90
|
}).then(function () { return true; });
|
|
77
91
|
};
|
|
78
92
|
/**
|
|
@@ -93,8 +107,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
93
107
|
var _this = this;
|
|
94
108
|
return this.getSplit(name).then(function (split) {
|
|
95
109
|
if (split) {
|
|
96
|
-
_this._decrementCounts(split);
|
|
110
|
+
return _this._decrementCounts(split).then(function () { return _this._updateFlagSets(name, split.sets); });
|
|
97
111
|
}
|
|
112
|
+
}).then(function () {
|
|
98
113
|
return _this.redis.del(_this.keys.buildSplitKey(name));
|
|
99
114
|
});
|
|
100
115
|
};
|
|
@@ -169,14 +184,20 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
169
184
|
return this.redis.keys(this.keys.searchPatternForSplitKeys()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
|
|
170
185
|
};
|
|
171
186
|
/**
|
|
172
|
-
* Get list of
|
|
173
|
-
* The returned promise is resolved with the list of
|
|
174
|
-
* or rejected if
|
|
175
|
-
* @todo this is a no-op method to be implemented
|
|
187
|
+
* Get list of feature flag names related to a given list of flag set names.
|
|
188
|
+
* The returned promise is resolved with the list of feature flag names per flag set,
|
|
189
|
+
* or rejected if the pipelined redis operation fails (e.g., timeout).
|
|
176
190
|
*/
|
|
177
|
-
SplitsCacheInRedis.prototype.getNamesByFlagSets = function () {
|
|
178
|
-
|
|
179
|
-
return
|
|
191
|
+
SplitsCacheInRedis.prototype.getNamesByFlagSets = function (flagSets) {
|
|
192
|
+
var _this = this;
|
|
193
|
+
return this.redis.pipeline(flagSets.map(function (flagSet) { return ['smembers', _this.keys.buildFlagSetKey(flagSet)]; })).exec()
|
|
194
|
+
.then(function (results) { return results.map(function (_a, index) {
|
|
195
|
+
var e = _a[0], value = _a[1];
|
|
196
|
+
if (e === null)
|
|
197
|
+
return value;
|
|
198
|
+
_this.log.error(LOG_PREFIX + ("Could not read result from get members of flag set " + flagSets[index] + " due to an error: " + e));
|
|
199
|
+
}); })
|
|
200
|
+
.then(function (namesByFlagSets) { return namesByFlagSets.map(function (namesByFlagSet) { return new _Set(namesByFlagSet); }); });
|
|
180
201
|
};
|
|
181
202
|
/**
|
|
182
203
|
* Check traffic type existence.
|
|
@@ -193,24 +214,20 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
193
214
|
return false; // if entry doesn't exist, means that TT doesn't exist
|
|
194
215
|
ttCount = parseInt(ttCount, 10);
|
|
195
216
|
if (!isFiniteNumber(ttCount) || ttCount < 0) {
|
|
196
|
-
_this.log.info(LOG_PREFIX + ("Could not validate traffic type
|
|
217
|
+
_this.log.info(LOG_PREFIX + ("Could not validate traffic type existence of " + trafficType + " due to data corruption of some sorts."));
|
|
197
218
|
return false;
|
|
198
219
|
}
|
|
199
220
|
return ttCount > 0;
|
|
200
221
|
})
|
|
201
222
|
.catch(function (e) {
|
|
202
|
-
_this.log.error(LOG_PREFIX + ("Could not validate traffic type
|
|
223
|
+
_this.log.error(LOG_PREFIX + ("Could not validate traffic type existence of " + trafficType + " due to an error: " + e + "."));
|
|
203
224
|
// If there is an error, bypass the validation so the event can get tracked.
|
|
204
225
|
return true;
|
|
205
226
|
});
|
|
206
227
|
};
|
|
207
|
-
|
|
208
|
-
* Delete everything in the current database.
|
|
209
|
-
*
|
|
210
|
-
* @NOTE documentation says it never fails.
|
|
211
|
-
*/
|
|
228
|
+
// @TODO remove or implement. It is not being used.
|
|
212
229
|
SplitsCacheInRedis.prototype.clear = function () {
|
|
213
|
-
return
|
|
230
|
+
return Promise.resolve();
|
|
214
231
|
};
|
|
215
232
|
/**
|
|
216
233
|
* Fetches multiple splits definitions.
|