From c3f2d88af39786ad9e8fb644e8a16e3e6e690bda Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:09:18 -0700 Subject: [PATCH] feat: Remove index and custom event sampling. (#289) --- .../src/featureStore/index.ts | 12 --- .../internal/events/EventProcessor.test.ts | 101 ------------------ .../src/internal/events/EventProcessor.ts | 4 +- .../src/internal/events/InputCustomEvent.ts | 3 +- .../src/internal/events/InputEvalEvent.ts | 1 - .../src/internal/events/LDEventOverrides.ts | 29 ----- .../common/src/internal/events/index.ts | 2 - .../src/api/EdgeFeatureStore.ts | 12 --- .../data_sources/PollingProcessor.test.ts | 6 -- .../data_sources/StreamingProcessor.test.ts | 72 +++++-------- .../__tests__/events/EventProcessor.test.ts | 2 - .../__tests__/store/serialization.test.ts | 86 ++------------- .../shared/sdk-server/src/LDClientImpl.ts | 72 ++----------- .../src/data_sources/FileDataSource.ts | 6 -- .../src/data_sources/PollingProcessor.ts | 3 - .../src/data_sources/StreamingProcessor.ts | 3 - .../sdk-server/src/events/EventFactory.ts | 12 +-- .../shared/sdk-server/src/store/Metric.ts | 5 - .../shared/sdk-server/src/store/Override.ts | 5 - .../src/store/VersionedDataKinds.ts | 10 -- .../sdk-server/src/store/serialization.ts | 16 +-- .../__tests__/RedisCore.test.ts | 52 --------- 22 files changed, 52 insertions(+), 462 deletions(-) delete mode 100644 packages/shared/common/src/internal/events/LDEventOverrides.ts delete mode 100644 packages/shared/sdk-server/src/store/Metric.ts delete mode 100644 packages/shared/sdk-server/src/store/Override.ts diff --git a/packages/shared/akamai-edgeworker-sdk/src/featureStore/index.ts b/packages/shared/akamai-edgeworker-sdk/src/featureStore/index.ts index 68b02ddef..812ae1dfa 100644 --- a/packages/shared/akamai-edgeworker-sdk/src/featureStore/index.ts +++ b/packages/shared/akamai-edgeworker-sdk/src/featureStore/index.ts @@ -59,12 +59,6 @@ export class EdgeFeatureStore implements LDFeatureStore { case 'segments': callback(item.segments[dataKey]); break; - case 'configurationOverrides': - callback(item.configurationOverrides?.[dataKey] ?? null); - break; - case 'metrics': - callback(item.metrics?.[dataKey] ?? null); - break; default: callback(null); } @@ -96,12 +90,6 @@ export class EdgeFeatureStore implements LDFeatureStore { case 'segments': callback(item.segments); break; - case 'configurationOverrides': - callback(item.configurationOverrides || {}); - break; - case 'metrics': - callback(item.metrics || {}); - break; default: throw new Error(`Unsupported DataKind: ${namespace}`); } diff --git a/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts b/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts index 5bc17c794..860b31811 100644 --- a/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts +++ b/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts @@ -295,7 +295,6 @@ describe('given an event processor', () => { trackEvents: true, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -326,7 +325,6 @@ describe('given an event processor', () => { trackEvents: true, default: 'default', samplingRatio: 2, - indexSamplingRatio: 1, // Disable the index events. withReasons: true, }); @@ -360,7 +358,6 @@ describe('given an event processor', () => { trackEvents: true, default: 'default', samplingRatio: 2, - indexSamplingRatio: 1, // Disable the index events. withReasons: true, }); @@ -379,36 +376,6 @@ describe('given an event processor', () => { ]); }); - it('excludes index events that are not sampled', async () => { - // @ts-ignore - shouldSample.mockImplementation((ratio) => ratio === 2); - Date.now = jest.fn(() => 1000); - eventProcessor.sendEvent({ - kind: 'feature', - creationDate: 1000, - context: Context.fromLDContext(user), - key: 'flagkey', - version: 11, - variation: 1, - value: 'value', - trackEvents: true, - default: 'default', - samplingRatio: 2, - indexSamplingRatio: 1, // Disable the index events. - withReasons: true, - }); - - await eventProcessor.flush(); - const request = await eventSender.queue.take(); - expect(shouldSample).toHaveBeenCalledWith(2); - expect(shouldSample).toHaveBeenCalledWith(1); - - expect(request.data).toEqual([ - { ...makeFeatureEvent(1000, 11), samplingRatio: 2 }, - makeSummary(1000, 1000, 1, 11), - ]); - }); - it('handles the version being 0', async () => { Date.now = jest.fn(() => 1000); eventProcessor.sendEvent({ @@ -422,7 +389,6 @@ describe('given an event processor', () => { trackEvents: true, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -455,7 +421,6 @@ describe('given an event processor', () => { debugEventsUntilDate: 2000, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -487,7 +452,6 @@ describe('given an event processor', () => { debugEventsUntilDate: 2000, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -526,7 +490,6 @@ describe('given an event processor', () => { debugEventsUntilDate: 1500, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -558,7 +521,6 @@ describe('given an event processor', () => { trackEvents: true, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); eventProcessor.sendEvent({ @@ -572,7 +534,6 @@ describe('given an event processor', () => { trackEvents: true, default: 'potato', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -637,7 +598,6 @@ describe('given an event processor', () => { trackEvents: false, default: 'default', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); eventProcessor.sendEvent({ @@ -651,7 +611,6 @@ describe('given an event processor', () => { trackEvents: false, default: 'potato', samplingRatio: 1, - indexSamplingRatio: 1, withReasons: true, }); @@ -709,42 +668,6 @@ describe('given an event processor', () => { key: 'eventkey', data: { thing: 'stuff' }, samplingRatio: 1, - indexSamplingRatio: 1, - }); - - await eventProcessor.flush(); - const request = await eventSender.queue.take(); - - expect(request.data).toEqual([ - { - kind: 'index', - creationDate: 1000, - context: { ...user, kind: 'user' }, - }, - { - kind: 'custom', - key: 'eventkey', - data: { thing: 'stuff' }, - creationDate: 1000, - contextKeys: { - user: 'userKey', - }, - }, - ]); - }); - - it('does not queue a custom event that is not sampled', async () => { - // @ts-ignore - shouldSample.mockImplementation((ratio) => ratio !== 2); - Date.now = jest.fn(() => 1000); - eventProcessor.sendEvent({ - kind: 'custom', - creationDate: 1000, - context: Context.fromLDContext(user), - key: 'eventkey', - data: { thing: 'stuff' }, - samplingRatio: 2, - indexSamplingRatio: 1, }); await eventProcessor.flush(); @@ -756,27 +679,6 @@ describe('given an event processor', () => { creationDate: 1000, context: { ...user, kind: 'user' }, }, - ]); - }); - - it('does not queue a index event that is not sampled with a custom event', async () => { - // @ts-ignore - shouldSample.mockImplementation((ratio) => ratio === 2); - Date.now = jest.fn(() => 1000); - eventProcessor.sendEvent({ - kind: 'custom', - creationDate: 1000, - context: Context.fromLDContext(user), - key: 'eventkey', - data: { thing: 'stuff' }, - samplingRatio: 2, - indexSamplingRatio: 1, - }); - - await eventProcessor.flush(); - const request = await eventSender.queue.take(); - - expect(request.data).toEqual([ { kind: 'custom', key: 'eventkey', @@ -785,7 +687,6 @@ describe('given an event processor', () => { contextKeys: { user: 'userKey', }, - samplingRatio: 2, }, ]); }); @@ -798,7 +699,6 @@ describe('given an event processor', () => { key: 'eventkey', data: { thing: 'stuff' }, samplingRatio: 1, - indexSamplingRatio: 1, }); await eventProcessor.flush(); @@ -832,7 +732,6 @@ describe('given an event processor', () => { data: { thing: 'stuff' }, metricValue: 1.5, samplingRatio: 1, - indexSamplingRatio: 1, }); await eventProcessor.flush(); diff --git a/packages/shared/common/src/internal/events/EventProcessor.ts b/packages/shared/common/src/internal/events/EventProcessor.ts index 4b847c18a..8ed346764 100644 --- a/packages/shared/common/src/internal/events/EventProcessor.ts +++ b/packages/shared/common/src/internal/events/EventProcessor.ts @@ -251,14 +251,14 @@ export default class EventProcessor implements LDEventProcessor { const addIndexEvent = shouldNotDeduplicate && !isIdentifyEvent; - if (addIndexEvent && shouldSample(inputEvent.indexSamplingRatio)) { + if (addIndexEvent) { this.enqueue( this.makeOutputEvent( { kind: 'index', creationDate: inputEvent.creationDate, context: inputEvent.context, - samplingRatio: inputEvent.indexSamplingRatio, + samplingRatio: 1, }, false, ), diff --git a/packages/shared/common/src/internal/events/InputCustomEvent.ts b/packages/shared/common/src/internal/events/InputCustomEvent.ts index 5e6fa2ae1..1c0c4a2b3 100644 --- a/packages/shared/common/src/internal/events/InputCustomEvent.ts +++ b/packages/shared/common/src/internal/events/InputCustomEvent.ts @@ -10,8 +10,9 @@ export default class InputCustomEvent { public readonly key: string, public readonly data?: any, public readonly metricValue?: number, + // Currently custom events are not sampled, but this is here to make the handling + // code more uniform. public readonly samplingRatio: number = 1, - public readonly indexSamplingRatio: number = 1, ) { this.creationDate = Date.now(); this.context = context; diff --git a/packages/shared/common/src/internal/events/InputEvalEvent.ts b/packages/shared/common/src/internal/events/InputEvalEvent.ts index 201f47beb..ce7e24727 100644 --- a/packages/shared/common/src/internal/events/InputEvalEvent.ts +++ b/packages/shared/common/src/internal/events/InputEvalEvent.ts @@ -38,7 +38,6 @@ export default class InputEvalEvent { debugEventsUntilDate?: number, excludeFromSummaries?: boolean, public readonly samplingRatio: number = 1, - public readonly indexSamplingRatio: number = 1, ) { this.creationDate = Date.now(); this.default = defValue; diff --git a/packages/shared/common/src/internal/events/LDEventOverrides.ts b/packages/shared/common/src/internal/events/LDEventOverrides.ts deleted file mode 100644 index 459e0d6fa..000000000 --- a/packages/shared/common/src/internal/events/LDEventOverrides.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Represents an override for a specific custom event. - * - * This does not use the data store type, because storage would not be shared between - * client and server implementations. - */ -export interface LDMetricOverride { - samplingRatio?: number; -} - -/** - * Interfaces for accessing dynamic event configuration data from LaunchDarkly. - * - * LaunchDarkly may adjust the rate of sampling of specific event types, or - * specific custom events. - */ -export interface LDEventOverrides { - /** - * Get the sampling ratio for a custom event. - * - * @param key A key of a custom event. - */ - samplingRatio(key: string): Promise; - - /** - * Get the sampling ratio for index events. - */ - indexEventSamplingRatio(): Promise; -} diff --git a/packages/shared/common/src/internal/events/index.ts b/packages/shared/common/src/internal/events/index.ts index a124929c8..80a44f9e1 100644 --- a/packages/shared/common/src/internal/events/index.ts +++ b/packages/shared/common/src/internal/events/index.ts @@ -4,7 +4,6 @@ import InputEvalEvent from './InputEvalEvent'; import InputEvent from './InputEvent'; import InputIdentifyEvent from './InputIdentifyEvent'; import InputMigrationEvent from './InputMigrationEvent'; -import { LDEventOverrides } from './LDEventOverrides'; import shouldSample from './sampling'; export { @@ -14,6 +13,5 @@ export { InputIdentifyEvent, InputMigrationEvent, EventProcessor, - LDEventOverrides, shouldSample, }; diff --git a/packages/shared/sdk-server-edge/src/api/EdgeFeatureStore.ts b/packages/shared/sdk-server-edge/src/api/EdgeFeatureStore.ts index 8cdd897db..933943d20 100644 --- a/packages/shared/sdk-server-edge/src/api/EdgeFeatureStore.ts +++ b/packages/shared/sdk-server-edge/src/api/EdgeFeatureStore.ts @@ -52,12 +52,6 @@ export class EdgeFeatureStore implements LDFeatureStore { case 'segments': callback(item.segments[dataKey]); break; - case 'configurationOverrides': - callback(item.configurationOverrides?.[dataKey] ?? null); - break; - case 'metrics': - callback(item.metrics?.[dataKey] ?? null); - break; default: callback(null); } @@ -89,12 +83,6 @@ export class EdgeFeatureStore implements LDFeatureStore { case 'segments': callback(item.segments); break; - case 'configurationOverrides': - callback(item.configurationOverrides || {}); - break; - case 'metrics': - callback(item.metrics || {}); - break; default: callback({}); } diff --git a/packages/shared/sdk-server/__tests__/data_sources/PollingProcessor.test.ts b/packages/shared/sdk-server/__tests__/data_sources/PollingProcessor.test.ts index 7822c5e31..75b0bec17 100644 --- a/packages/shared/sdk-server/__tests__/data_sources/PollingProcessor.test.ts +++ b/packages/shared/sdk-server/__tests__/data_sources/PollingProcessor.test.ts @@ -19,8 +19,6 @@ describe('given an event processor', () => { const allData = { flags: { flag: { version: 1 } }, segments: { segment: { version: 1 } }, - configurationOverrides: { override: { version: 1 } }, - metrics: { metric: { version: 1 } }, }; const jsonData = JSON.stringify(allData); @@ -74,10 +72,6 @@ describe('given an event processor', () => { expect(flags).toEqual(allData.flags); const segments = await storeFacade.all(VersionedDataKinds.Segments); expect(segments).toEqual(allData.segments); - const configurationOverrides = await storeFacade.all(VersionedDataKinds.ConfigurationOverrides); - expect(configurationOverrides).toEqual(allData.configurationOverrides); - const metrics = await storeFacade.all(VersionedDataKinds.Metrics); - expect(metrics).toEqual(allData.metrics); }); }); diff --git a/packages/shared/sdk-server/__tests__/data_sources/StreamingProcessor.test.ts b/packages/shared/sdk-server/__tests__/data_sources/StreamingProcessor.test.ts index fababa968..23692184c 100644 --- a/packages/shared/sdk-server/__tests__/data_sources/StreamingProcessor.test.ts +++ b/packages/shared/sdk-server/__tests__/data_sources/StreamingProcessor.test.ts @@ -118,12 +118,6 @@ describe('given a stream processor with mock event source', () => { segments: { segkey: { key: 'segkey', version: 2 }, }, - configurationOverrides: { - configKey: { key: 'configKey', version: 3 }, - }, - metrics: { - metricKey: { key: 'metricKey', version: 4 }, - }, }, }; @@ -137,10 +131,6 @@ describe('given a stream processor with mock event source', () => { expect(f?.version).toEqual(1); const s = await asyncStore.get(VersionedDataKinds.Segments, 'segkey'); expect(s?.version).toEqual(2); - const override = await asyncStore.get(VersionedDataKinds.ConfigurationOverrides, 'configKey'); - expect(override?.version).toEqual(3); - const metric = await asyncStore.get(VersionedDataKinds.Metrics, 'metricKey'); - expect(metric?.version).toEqual(4); }); it('calls initialization callback', async () => { @@ -174,23 +164,21 @@ describe('given a stream processor with mock event source', () => { }); describe('when patching a message', () => { - it.each([ - VersionedDataKinds.Features, - VersionedDataKinds.Segments, - VersionedDataKinds.ConfigurationOverrides, - VersionedDataKinds.Metrics, - ])('patches a item of each kind: %j', async (kind) => { - streamProcessor.start(); - const patchData = { - path: `${kind.streamApiPath}itemKey`, - data: { key: 'itemKey', version: 1 }, - }; - - es.handlers.patch({ data: JSON.stringify(patchData) }); - - const f = await asyncStore.get(kind, 'itemKey'); - expect(f!.version).toEqual(1); - }); + it.each([VersionedDataKinds.Features, VersionedDataKinds.Segments])( + 'patches a item of each kind: %j', + async (kind) => { + streamProcessor.start(); + const patchData = { + path: `${kind.streamApiPath}itemKey`, + data: { key: 'itemKey', version: 1 }, + }; + + es.handlers.patch({ data: JSON.stringify(patchData) }); + + const f = await asyncStore.get(kind, 'itemKey'); + expect(f!.version).toEqual(1); + }, + ); it('passes error to callback if data is invalid', async () => { streamProcessor.start(); @@ -203,25 +191,23 @@ describe('given a stream processor with mock event source', () => { }); describe('when deleting a message', () => { - it.each([ - VersionedDataKinds.Features, - VersionedDataKinds.Segments, - VersionedDataKinds.ConfigurationOverrides, - VersionedDataKinds.Metrics, - ])('deletes each data kind: %j', async (kind) => { - streamProcessor.start(); - const item = { key: 'itemKey', version: 1 }; - await asyncStore.upsert(kind, item); - const stored = await asyncStore.get(kind, 'itemKey'); - expect(stored!.version).toEqual(1); + it.each([VersionedDataKinds.Features, VersionedDataKinds.Segments])( + 'deletes each data kind: %j', + async (kind) => { + streamProcessor.start(); + const item = { key: 'itemKey', version: 1 }; + await asyncStore.upsert(kind, item); + const stored = await asyncStore.get(kind, 'itemKey'); + expect(stored!.version).toEqual(1); - const deleteData = { path: `${kind.streamApiPath}${item.key}`, version: 2 }; + const deleteData = { path: `${kind.streamApiPath}${item.key}`, version: 2 }; - es.handlers.delete({ data: JSON.stringify(deleteData) }); + es.handlers.delete({ data: JSON.stringify(deleteData) }); - const stored2 = await asyncStore.get(VersionedDataKinds.Features, 'itemKey'); - expect(stored2).toBe(null); - }); + const stored2 = await asyncStore.get(VersionedDataKinds.Features, 'itemKey'); + expect(stored2).toBe(null); + }, + ); it('passes error to callback if data is invalid', async () => { streamProcessor.start(); diff --git a/packages/shared/sdk-server/__tests__/events/EventProcessor.test.ts b/packages/shared/sdk-server/__tests__/events/EventProcessor.test.ts index 5a114ae90..7cf4a9cf7 100644 --- a/packages/shared/sdk-server/__tests__/events/EventProcessor.test.ts +++ b/packages/shared/sdk-server/__tests__/events/EventProcessor.test.ts @@ -345,7 +345,6 @@ describe('given an event processor with diagnostics manager', () => { creationDate: 1000, context, samplingRatio: 1, - indexSamplingRatio: 1, }); eventProcessor.sendEvent({ kind: 'custom', @@ -353,7 +352,6 @@ describe('given an event processor with diagnostics manager', () => { creationDate: 1001, context, samplingRatio: 1, - indexSamplingRatio: 1, }); await eventProcessor.flush(); diff --git a/packages/shared/sdk-server/__tests__/store/serialization.test.ts b/packages/shared/sdk-server/__tests__/store/serialization.test.ts index 9e4264a3f..a18ac959d 100644 --- a/packages/shared/sdk-server/__tests__/store/serialization.test.ts +++ b/packages/shared/sdk-server/__tests__/store/serialization.test.ts @@ -152,13 +152,11 @@ const segmentWithBucketBy = { deleted: false, }; -function makeAllData(flag?: any, segment?: any, override?: any, metric?: any): any { +function makeAllData(flag?: any, segment?: any): any { const allData: any = { data: { flags: {}, segments: {}, - configurationOverrides: {}, - metrics: {}, }, }; @@ -168,38 +166,26 @@ function makeAllData(flag?: any, segment?: any, override?: any, metric?: any): a if (segment) { allData.data.segments.segmentName = segment; } - if (override) { - allData.data.configurationOverrides.overrideName = override; - } - if (metric) { - allData.data.metrics.metricName = metric; - } return allData; } -function makeSerializedAllData(flag?: any, segment?: any, override?: any, metric?: any): string { - return JSON.stringify(makeAllData(flag, segment, override, metric)); +function makeSerializedAllData(flag?: any, segment?: any): string { + return JSON.stringify(makeAllData(flag, segment)); } -function makePatchData(flag?: any, segment?: any, override?: any, metric?: any): any { +function makePatchData(flag?: any, segment?: any): any { let path = '/flags/flagName'; if (segment) { path = '/segments/segmentName'; } - if (override) { - path = '/configurationOverrides/overrideName'; - } - if (metric) { - path = '/metrics/metricName'; - } return { path, - data: flag ?? segment ?? override ?? metric, + data: flag ?? segment, }; } -function makeSerializedPatchData(flag?: any, segment?: any, override?: any, metric?: any): string { - return JSON.stringify(makePatchData(flag, segment, override, metric)); +function makeSerializedPatchData(flag?: any, segment?: any): string { + return JSON.stringify(makePatchData(flag, segment)); } describe('when deserializing all data', () => { @@ -253,28 +239,6 @@ describe('when deserializing all data', () => { const ref = parsed?.data.flags.flagName.rules?.[0].rollout?.bucketByAttributeReference; expect(ref?.isValid).toBeTruthy(); }); - - it('handles a config override', () => { - const override = { - key: 'overrideName', - value: 'potato', - version: 1, - }; - const jsonString = makeSerializedAllData(undefined, undefined, override, undefined); - const parsed = deserializeAll(jsonString); - expect(parsed).toMatchObject({ data: { configurationOverrides: { overrideName: override } } }); - }); - - it('handles a metric', () => { - const metric = { - key: 'metricName', - samplingRatio: 42, - version: 1, - }; - const jsonString = makeSerializedAllData(undefined, undefined, undefined, metric); - const parsed = deserializeAll(jsonString); - expect(parsed).toMatchObject({ data: { metrics: { metricName: metric } } }); - }); }); describe('when deserializing patch data', () => { @@ -326,42 +290,6 @@ describe('when deserializing patch data', () => { const ref = (parsed?.data as Flag).rules?.[0].rollout?.bucketByAttributeReference; expect(ref?.isValid).toBeTruthy(); }); - - it('handles a config override', () => { - const override = { - key: 'overrideName', - value: 'potato', - version: 1, - }; - const jsonString = makeSerializedPatchData(undefined, undefined, override, undefined); - const parsed = deserializePatch(jsonString); - expect(parsed).toEqual({ - data: override, - path: '/configurationOverrides/overrideName', - kind: { - namespace: 'configurationOverrides', - streamApiPath: '/configurationOverrides/', - }, - }); - }); - - it('handles a metric', () => { - const metric = { - key: 'metricName', - samplingRatio: 42, - version: 1, - }; - const jsonString = makeSerializedPatchData(undefined, undefined, undefined, metric); - const parsed = deserializePatch(jsonString); - expect(parsed).toEqual({ - data: metric, - path: '/metrics/metricName', - kind: { - namespace: 'metrics', - streamApiPath: '/metrics/', - }, - }); - }); }); it('removes null elements', () => { diff --git a/packages/shared/sdk-server/src/LDClientImpl.ts b/packages/shared/sdk-server/src/LDClientImpl.ts index bb75b180b..c9347ab80 100644 --- a/packages/shared/sdk-server/src/LDClientImpl.ts +++ b/packages/shared/sdk-server/src/LDClientImpl.ts @@ -54,8 +54,6 @@ import MigrationOpEventToInputEvent from './MigrationOpEventConversion'; import MigrationOpTracker from './MigrationOpTracker'; import Configuration from './options/Configuration'; import AsyncStoreFacade from './store/AsyncStoreFacade'; -import { Metric } from './store/Metric'; -import { Override } from './store/Override'; import VersionedDataKinds from './store/VersionedDataKinds'; enum InitState { @@ -115,8 +113,6 @@ export default class LDClientImpl implements LDClient { private diagnosticsManager?: DiagnosticsManager; - private eventConfig: internal.LDEventOverrides; - /** * Intended for use by platform specific client implementations. * @@ -236,26 +232,6 @@ export default class LDClientImpl implements LDClient { this.onReady(); } }); - - this.eventConfig = { - samplingRatio: async (key: string) => { - const ratioItem = await this.asyncFeatureStore.get(VersionedDataKinds.Metrics, key); - if (ratioItem && !ratioItem.deleted) { - return (ratioItem as Metric).samplingRatio ?? 1; - } - return 1; - }, - indexEventSamplingRatio: async () => { - const indexSampling = await this.asyncFeatureStore.get( - VersionedDataKinds.ConfigurationOverrides, - 'indexSamplingRatio', - ); - if (indexSampling && !indexSampling.deleted) { - return (indexSampling as Override).value ?? 1; - } - return 1; - }, - }; } initialized(): boolean { @@ -577,20 +553,10 @@ export default class LDClientImpl implements LDClient { this.logger?.warn(ClientMessages.missingContextKeyNoEvent); return; } - // Async immediately invoking function expression to get the flag from the store - // without requiring track to be async. - (async () => { - this.eventProcessor.sendEvent( - this.eventFactoryDefault.customEvent( - key, - checkedContext!, - data, - metricValue, - await this.eventConfig.samplingRatio(key), - await this.eventConfig.indexEventSamplingRatio(), - ), - ); - })(); + + this.eventProcessor.sendEvent( + this.eventFactoryDefault.customEvent(key, checkedContext!, data, metricValue), + ); } trackMigration(event: LDMigrationOpEvent): void { @@ -652,17 +618,9 @@ export default class LDClientImpl implements LDClient { ); this.onError(error); const result = EvalResult.forError(ErrorKinds.FlagNotFound, undefined, defaultValue); - (async () => { - const indexSamplingRatio = await this.eventConfig.indexEventSamplingRatio(); - this.eventProcessor.sendEvent( - this.eventFactoryDefault.unknownFlagEvent( - flagKey, - evalContext, - result.detail, - indexSamplingRatio, - ), - ); - })(); + this.eventProcessor.sendEvent( + this.eventFactoryDefault.unknownFlagEvent(flagKey, evalContext, result.detail), + ); cb(result); return; } @@ -686,14 +644,12 @@ export default class LDClientImpl implements LDClient { `Did not receive expected type (${type}) evaluating feature flag "${flagKey}"`, defaultValue, ); - // Method intentionally not awaited, puts event processing outside hot path. this.sendEvalEvent(evalRes, eventFactory, flag, evalContext, defaultValue); cb(errorRes, flag); return; } } - // Method intentionally not awaited, puts event processing outside hot path. this.sendEvalEvent(evalRes, eventFactory, flag, evalContext, defaultValue); cb(evalRes, flag); }, @@ -702,26 +658,18 @@ export default class LDClientImpl implements LDClient { }); } - private async sendEvalEvent( + private sendEvalEvent( evalRes: EvalResult, eventFactory: EventFactory, flag: Flag, evalContext: Context, defaultValue: any, ) { - const indexSamplingRatio = await this.eventConfig.indexEventSamplingRatio(); evalRes.events?.forEach((event) => { - this.eventProcessor.sendEvent({ ...event, indexSamplingRatio }); + this.eventProcessor.sendEvent({ ...event }); }); this.eventProcessor.sendEvent( - eventFactory.evalEvent( - flag, - evalContext, - evalRes.detail, - defaultValue, - undefined, - indexSamplingRatio, - ), + eventFactory.evalEvent(flag, evalContext, evalRes.detail, defaultValue, undefined), ); } diff --git a/packages/shared/sdk-server/src/data_sources/FileDataSource.ts b/packages/shared/sdk-server/src/data_sources/FileDataSource.ts index fccf40f53..c40209e0b 100644 --- a/packages/shared/sdk-server/src/data_sources/FileDataSource.ts +++ b/packages/shared/sdk-server/src/data_sources/FileDataSource.ts @@ -137,11 +137,5 @@ export default class FileDataSource implements LDStreamProcessor { processSegment(parsed.segments[key]); this.addItem(VersionedDataKinds.Segments, parsed.segments[key]); }); - Object.keys(parsed.configurationOverrides || {}).forEach((key) => { - this.addItem(VersionedDataKinds.ConfigurationOverrides, parsed.configurationOverrides[key]); - }); - Object.keys(parsed.metrics || {}).forEach((key) => { - this.addItem(VersionedDataKinds.Metrics, parsed.metrics[key]); - }); } } diff --git a/packages/shared/sdk-server/src/data_sources/PollingProcessor.ts b/packages/shared/sdk-server/src/data_sources/PollingProcessor.ts index 307691efe..a7af081a4 100644 --- a/packages/shared/sdk-server/src/data_sources/PollingProcessor.ts +++ b/packages/shared/sdk-server/src/data_sources/PollingProcessor.ts @@ -69,9 +69,6 @@ export default class PollingProcessor implements LDStreamProcessor { const initData = { [VersionedDataKinds.Features.namespace]: parsed.flags, [VersionedDataKinds.Segments.namespace]: parsed.segments, - [VersionedDataKinds.ConfigurationOverrides.namespace]: - parsed.configurationOverrides || {}, - [VersionedDataKinds.Metrics.namespace]: parsed.metrics || {}, }; this.featureStore.init(initData, () => { fn?.(); diff --git a/packages/shared/sdk-server/src/data_sources/StreamingProcessor.ts b/packages/shared/sdk-server/src/data_sources/StreamingProcessor.ts index 698121749..411657aff 100644 --- a/packages/shared/sdk-server/src/data_sources/StreamingProcessor.ts +++ b/packages/shared/sdk-server/src/data_sources/StreamingProcessor.ts @@ -131,9 +131,6 @@ export default class StreamingProcessor implements LDStreamProcessor { const initData = { [VersionedDataKinds.Features.namespace]: parsed.data.flags, [VersionedDataKinds.Segments.namespace]: parsed.data.segments, - [VersionedDataKinds.ConfigurationOverrides.namespace]: - parsed.data.configurationOverrides || {}, - [VersionedDataKinds.Metrics.namespace]: parsed.data.metrics || {}, }; this.featureStore.init(initData, () => fn?.()); diff --git a/packages/shared/sdk-server/src/events/EventFactory.ts b/packages/shared/sdk-server/src/events/EventFactory.ts index a996c1b5e..b9067971c 100644 --- a/packages/shared/sdk-server/src/events/EventFactory.ts +++ b/packages/shared/sdk-server/src/events/EventFactory.ts @@ -15,7 +15,6 @@ export default class EventFactory { detail: LDEvaluationDetail, defaultVal: any, prereqOfFlag?: Flag, - indexEventSamplingRatio?: number, ): internal.InputEvalEvent { const addExperimentData = isExperiment(flag, detail.reason); return new internal.InputEvalEvent( @@ -33,16 +32,10 @@ export default class EventFactory { flag.debugEventsUntilDate, flag.excludeFromSummaries, flag.samplingRatio, - indexEventSamplingRatio ?? 1, ); } - unknownFlagEvent( - key: string, - context: Context, - detail: LDEvaluationDetail, - indexEventSamplingRatio?: number, - ) { + unknownFlagEvent(key: string, context: Context, detail: LDEvaluationDetail) { return new internal.InputEvalEvent( this.withReasons, context, @@ -59,7 +52,6 @@ export default class EventFactory { undefined, // debugEventsUntilDate undefined, // exclude from summaries undefined, // sampling ratio - indexEventSamplingRatio, ); } @@ -76,7 +68,6 @@ export default class EventFactory { data?: any, metricValue?: number, samplingRatio: number = 1, - indexSamplingRatio: number = 1, ) { return new internal.InputCustomEvent( context, @@ -84,7 +75,6 @@ export default class EventFactory { data ?? undefined, metricValue ?? undefined, samplingRatio, - indexSamplingRatio, ); } } diff --git a/packages/shared/sdk-server/src/store/Metric.ts b/packages/shared/sdk-server/src/store/Metric.ts deleted file mode 100644 index ec42a4e28..000000000 --- a/packages/shared/sdk-server/src/store/Metric.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Versioned } from '../evaluation/data/Versioned'; - -export interface Metric extends Versioned { - samplingRatio?: number; -} diff --git a/packages/shared/sdk-server/src/store/Override.ts b/packages/shared/sdk-server/src/store/Override.ts deleted file mode 100644 index 37bc07524..000000000 --- a/packages/shared/sdk-server/src/store/Override.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Versioned } from '../evaluation/data/Versioned'; - -export interface Override extends Versioned { - value: any; -} diff --git a/packages/shared/sdk-server/src/store/VersionedDataKinds.ts b/packages/shared/sdk-server/src/store/VersionedDataKinds.ts index 2ac0af241..0052e18ae 100644 --- a/packages/shared/sdk-server/src/store/VersionedDataKinds.ts +++ b/packages/shared/sdk-server/src/store/VersionedDataKinds.ts @@ -16,14 +16,4 @@ export default class VersionedDataKinds { namespace: 'segments', streamApiPath: '/segments/', }; - - static readonly ConfigurationOverrides: VersionedDataKind = { - namespace: 'configurationOverrides', - streamApiPath: '/configurationOverrides/', - }; - - static readonly Metrics: VersionedDataKind = { - namespace: 'metrics', - streamApiPath: '/metrics/', - }; } diff --git a/packages/shared/sdk-server/src/store/serialization.ts b/packages/shared/sdk-server/src/store/serialization.ts index 9c3a51243..8c9f545af 100644 --- a/packages/shared/sdk-server/src/store/serialization.ts +++ b/packages/shared/sdk-server/src/store/serialization.ts @@ -8,8 +8,6 @@ import { VersionedData } from '../api/interfaces'; import { Flag } from '../evaluation/data/Flag'; import { Rollout } from '../evaluation/data/Rollout'; import { Segment } from '../evaluation/data/Segment'; -import { Metric } from './Metric'; -import { Override } from './Override'; import VersionedDataKinds, { VersionedDataKind } from './VersionedDataKinds'; // The max size where we use an array instead of a set. @@ -31,8 +29,6 @@ export function reviver(this: any, key: string, value: any): any { interface AllData { flags: { [name: string]: Flag }; segments: { [name: string]: Segment }; - configurationOverrides?: { [name: string]: Override }; - metrics?: { [name: string]: Metric }; } interface AllDataStream { @@ -92,12 +88,10 @@ interface DeleteData extends Omit { type VersionedFlag = VersionedData & Flag; type VersionedSegment = VersionedData & Segment; -type VersionedOverride = VersionedData & Override; -type VersionedMetric = VersionedData & Metric; interface PatchData { path: string; - data: VersionedFlag | VersionedSegment | VersionedOverride | VersionedMetric; + data: VersionedFlag | VersionedSegment; kind?: VersionedDataKind; } @@ -262,10 +256,6 @@ export function deserializePatch(data: string): PatchData | undefined { } else if (parsed.path.startsWith(VersionedDataKinds.Segments.streamApiPath)) { processSegment(parsed.data as VersionedSegment); parsed.kind = VersionedDataKinds.Segments; - } else if (parsed.path.startsWith(VersionedDataKinds.ConfigurationOverrides.streamApiPath)) { - parsed.kind = VersionedDataKinds.ConfigurationOverrides; - } else if (parsed.path.startsWith(VersionedDataKinds.Metrics.streamApiPath)) { - parsed.kind = VersionedDataKinds.Metrics; } return parsed; @@ -283,10 +273,6 @@ export function deserializeDelete(data: string): DeleteData | undefined { parsed.kind = VersionedDataKinds.Features; } else if (parsed.path.startsWith(VersionedDataKinds.Segments.streamApiPath)) { parsed.kind = VersionedDataKinds.Segments; - } else if (parsed.path.startsWith(VersionedDataKinds.ConfigurationOverrides.streamApiPath)) { - parsed.kind = VersionedDataKinds.ConfigurationOverrides; - } else if (parsed.path.startsWith(VersionedDataKinds.Metrics.streamApiPath)) { - parsed.kind = VersionedDataKinds.Metrics; } return parsed; } diff --git a/packages/store/node-server-sdk-redis/__tests__/RedisCore.test.ts b/packages/store/node-server-sdk-redis/__tests__/RedisCore.test.ts index de7d2d4f8..fffb1151d 100644 --- a/packages/store/node-server-sdk-redis/__tests__/RedisCore.test.ts +++ b/packages/store/node-server-sdk-redis/__tests__/RedisCore.test.ts @@ -6,17 +6,10 @@ import clearPrefix from './clearPrefix'; const featuresKind = { namespace: 'features', deserialize: (data: string) => JSON.parse(data) }; const segmentsKind = { namespace: 'segments', deserialize: (data: string) => JSON.parse(data) }; -const configurationOverridesKind = { - namespace: 'configurationOverrides', - deserialize: (data: string) => JSON.parse(data), -}; -const metricsKind = { namespace: 'metrics', deserialize: (data: string) => JSON.parse(data) }; const dataKind = { features: featuresKind, segments: segmentsKind, - configurationOverrides: configurationOverridesKind, - metrics: metricsKind, }; function promisify(method: (callback: (val: T) => void) => void): Promise { @@ -105,24 +98,14 @@ describe('given an empty store', () => { const segments = [ { key: 'first', item: { version: 2, serializedItem: `{"version":2}`, deleted: false } }, ]; - const configurationOverrides = [ - { key: 'first', item: { version: 1, serializedItem: `{"version":3}`, deleted: false } }, - ]; - const metrics = [ - { key: 'first', item: { version: 1, serializedItem: `{"version":4}`, deleted: false } }, - ]; await facade.init([ { key: dataKind.features, item: flags }, { key: dataKind.segments, item: segments }, - { key: dataKind.configurationOverrides, item: configurationOverrides }, - { key: dataKind.metrics, item: metrics }, ]); const items1 = await facade.getAll(dataKind.features); const items2 = await facade.getAll(dataKind.segments); - const overrides1 = await facade.getAll(dataKind.configurationOverrides); - const metrics1 = await facade.getAll(dataKind.metrics); // Reading from the store will not maintain the version. expect(items1).toEqual([ @@ -142,43 +125,20 @@ describe('given an empty store', () => { }, ]); - expect(overrides1).toEqual([ - { - key: 'first', - item: { version: 0, deleted: false, serializedItem: '{"version":3}' }, - }, - ]); - expect(metrics1).toEqual([ - { - key: 'first', - item: { version: 0, deleted: false, serializedItem: '{"version":4}' }, - }, - ]); - const newFlags = [ { key: 'first', item: { version: 2, serializedItem: `{"version":2}`, deleted: false } }, ]; const newSegments = [ { key: 'first', item: { version: 3, serializedItem: `{"version":3}`, deleted: false } }, ]; - const newOverrides = [ - { key: 'first', item: { version: 2, serializedItem: `{"version":5}`, deleted: false } }, - ]; - const newMetrics = [ - { key: 'first', item: { version: 3, serializedItem: `{"version":6}`, deleted: false } }, - ]; await facade.init([ { key: dataKind.features, item: newFlags }, { key: dataKind.segments, item: newSegments }, - { key: dataKind.configurationOverrides, item: newOverrides }, - { key: dataKind.metrics, item: newMetrics }, ]); const items3 = await facade.getAll(dataKind.features); const items4 = await facade.getAll(dataKind.segments); - const overrides2 = await facade.getAll(dataKind.configurationOverrides); - const metrics2 = await facade.getAll(dataKind.metrics); expect(items3).toEqual([ { @@ -192,18 +152,6 @@ describe('given an empty store', () => { item: { version: 0, deleted: false, serializedItem: '{"version":3}' }, }, ]); - expect(overrides2).toEqual([ - { - key: 'first', - item: { version: 0, deleted: false, serializedItem: '{"version":5}' }, - }, - ]); - expect(metrics2).toEqual([ - { - key: 'first', - item: { version: 0, deleted: false, serializedItem: '{"version":6}' }, - }, - ]); }); });