Skip to content

Commit 2e3a4fd

Browse files
Todd AndersonTodd Anderson
authored andcommitted
Merge branch 'ta/fdv2-temporary-holding' into ta/sdk-851/polling-synchronizer
2 parents 9b9abf3 + e2c26af commit 2e3a4fd

File tree

8 files changed

+115
-26
lines changed

8 files changed

+115
-26
lines changed

packages/shared/common/__tests__/subsystem/DataSystem/CompositeDataSource.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,74 @@ it('is well behaved with an initializer and no synchronizers configured', async
516516
'CompositeDataSource has exhausted all configured datasources (1 initializers, 0 synchronizers).',
517517
});
518518
});
519+
520+
it('consumes cancellation tokens correctly', async () => {
521+
const mockInitializer1 = {
522+
start: jest
523+
.fn()
524+
.mockImplementation(
525+
(
526+
_dataCallback: (basis: boolean, data: any) => void,
527+
_statusCallback: (status: DataSourceState, err?: any) => void,
528+
) => {
529+
_dataCallback(true, { key: 'init1' });
530+
},
531+
),
532+
stop: jest.fn(),
533+
};
534+
535+
const mockSynchronizer1 = {
536+
start: jest
537+
.fn()
538+
.mockImplementation(
539+
(
540+
_dataCallback: (basis: boolean, data: any) => void,
541+
_statusCallback: (status: DataSourceState, err?: any) => void,
542+
) => {
543+
_statusCallback(DataSourceState.Initializing);
544+
_statusCallback(DataSourceState.Interrupted); // report interrupted to schedule automatic transition and create cancellation token
545+
},
546+
),
547+
stop: jest.fn(),
548+
};
549+
550+
const underTest = new CompositeDataSource(
551+
[makeInitializerFactory(mockInitializer1)],
552+
[makeSynchronizerFactory(mockSynchronizer1)],
553+
undefined,
554+
{
555+
// pass in transition condition of 0 so that it will thrash, generating cancellation tokens repeatedly
556+
[DataSourceState.Interrupted]: {
557+
durationMS: 100,
558+
transition: 'fallback',
559+
},
560+
},
561+
makeZeroBackoff(),
562+
);
563+
564+
let dataCallback;
565+
let statusCallback;
566+
let interruptedCount = 0;
567+
await new Promise<void>((resolve) => {
568+
dataCallback = jest.fn();
569+
statusCallback = jest.fn((_1: DataSourceState, _2: any) => {
570+
interruptedCount += 1;
571+
if (interruptedCount > 10) {
572+
// let it thrash for N iterations
573+
resolve();
574+
}
575+
});
576+
577+
underTest.start(dataCallback, statusCallback);
578+
});
579+
580+
// @ts-ignore
581+
// eslint-disable-next-line no-underscore-dangle
582+
expect(underTest._cancelTokens.length).toEqual(1);
583+
584+
underTest.stop();
585+
586+
// @ts-ignore
587+
// eslint-disable-next-line no-underscore-dangle
588+
expect(underTest._cancelTokens.length).toEqual(0);
589+
});

packages/shared/common/src/datasource/CompositeDataSource.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export class CompositeDataSource implements DataSource {
136136
cancelScheduledTransition = cancel;
137137
this._cancelTokens.push(cancelScheduledTransition);
138138
promise.then(() => {
139+
this._consumeCancelToken(cancel);
139140
callbackHandler.disable();
140141
transitionResolve({ transition: condition.transition });
141142
});
@@ -176,7 +177,10 @@ export class CompositeDataSource implements DataSource {
176177
const delay = this._backoff.fail();
177178
const { promise, cancel: cancelDelay } = this._cancellableDelay(delay);
178179
this._cancelTokens.push(cancelDelay);
179-
const delayedTransition = promise.then(() => transitionRequest);
180+
const delayedTransition = promise.then(() => {
181+
this._consumeCancelToken(cancelDelay);
182+
return transitionRequest;
183+
});
180184

181185
// race the delayed transition and external transition requests to be responsive
182186
transitionRequest = await Promise.race([

packages/shared/sdk-server/__tests__/options/Configuration.test.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function logger(options: LDOptions): TestLogger {
2222
describe.each([undefined, null, 'potat0', 17, [], {}])('constructed without options', (input) => {
2323
it('should have default options', () => {
2424
// JavaScript is not going to stop you from calling this with whatever
25-
// you want. So we need to tell TS to ingore our bad behavior.
25+
// you want. So we need to tell TS to ignore our bad behavior.
2626
// @ts-ignore
2727
const config = new Configuration(input);
2828

@@ -47,7 +47,7 @@ describe.each([undefined, null, 'potat0', 17, [], {}])('constructed without opti
4747
expect(config.tags.value).toBeUndefined();
4848
expect(config.timeout).toEqual(5);
4949
expect(config.tlsParams).toBeUndefined();
50-
expect(config.useLdd).toBe(false);
50+
expect(config.dataSystem.useLdd).toBe(false);
5151
expect(config.wrapperName).toBeUndefined();
5252
expect(config.wrapperVersion).toBeUndefined();
5353
expect(config.hooks).toBeUndefined();
@@ -233,7 +233,7 @@ describe('when setting different options', () => {
233233
])('allows setting stream and validates useLdd', (value, expected, warnings) => {
234234
// @ts-ignore
235235
const config = new Configuration(withLogger({ useLdd: value }));
236-
expect(config.useLdd).toEqual(expected);
236+
expect(config.dataSystem.useLdd).toEqual(expected);
237237
expect(logger(config).getCount()).toEqual(warnings);
238238
});
239239

@@ -421,7 +421,7 @@ describe('when setting different options', () => {
421421
]);
422422
});
423423

424-
it('drops invalid dataystem data source options and replaces with defaults', () => {
424+
it('drops invalid datasystem data source options and replaces with defaults', () => {
425425
const config = new Configuration(
426426
withLogger({
427427
dataSystem: { dataSource: { bogus: 'myBogusOptions' } as unknown as DataSourceOptions },
@@ -436,7 +436,7 @@ describe('when setting different options', () => {
436436
]);
437437
});
438438

439-
it('validates the datasystem persitent store is a factory or object', () => {
439+
it('validates the datasystem persistent store is a factory or object', () => {
440440
const config1 = new Configuration(
441441
withLogger({
442442
dataSystem: {
@@ -501,7 +501,7 @@ describe('when setting different options', () => {
501501
expect(logger(config).getCount()).toEqual(0);
502502
});
503503

504-
it('ignores top level featureStore in favor of the datasystem persitent store', () => {
504+
it('ignores top level featureStore in favor of the datasystem persistent store', () => {
505505
const shouldNotBeUsed = new InMemoryFeatureStore();
506506
const shouldBeUsed = new InMemoryFeatureStore();
507507
const config = new Configuration(
@@ -516,4 +516,29 @@ describe('when setting different options', () => {
516516
const result = config.dataSystem.featureStoreFactory(null);
517517
expect(result).toEqual(shouldBeUsed);
518518
});
519+
520+
it('ignores top level useLdd option if datasystem is specified', () => {
521+
const config = new Configuration(
522+
withLogger({
523+
dataSystem: {
524+
persistentStore: new InMemoryFeatureStore(),
525+
},
526+
useLdd: true,
527+
}),
528+
);
529+
const result = config.dataSystem.useLdd;
530+
expect(result).toEqual(undefined);
531+
532+
const config2 = new Configuration(
533+
withLogger({
534+
dataSystem: {
535+
persistentStore: new InMemoryFeatureStore(),
536+
useLdd: true,
537+
},
538+
useLdd: false,
539+
}),
540+
);
541+
const result2 = config2.dataSystem.useLdd;
542+
expect(result2).toEqual(true);
543+
});
519544
});

packages/shared/sdk-server/src/api/options/LDDataSystemOptions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ export interface LDDataSystemOptions {
3737
* type and the optional fields you want to customize.
3838
*
3939
* If not specified, this defaults to using the {@link StandardDataSourceOptions} which
40-
* pefroms a combination of streaming and polling.
40+
* performs a combination of streaming and polling.
4141
*
42-
* See {@link LDDataSystemOptions} decoumentation for exmaples.
42+
* See {@link LDDataSystemOptions} documentation for examples.
4343
*/
4444
dataSource?: DataSourceOptions;
4545

@@ -48,11 +48,11 @@ export interface LDDataSystemOptions {
4848
* data from the persistent store. Once fresh data has arrived from LaunchDarkly, the
4949
* SDK will no longer read from the persistent store, although it will keep it up-to-date
5050
* for future startups.
51-
*
51+
*
5252
* Some implementations provide the store implementation object itself, while others
5353
* provide a factory function that creates the store implementation based on the SDK
5454
* configuration; this property accepts either.
55-
*
55+
*
5656
* @param clientContext whose properties may be used to influence creation of the persistent store.
5757
*/
5858
persistentStore?: LDFeatureStore | ((clientContext: LDClientContext) => LDFeatureStore);
@@ -68,7 +68,7 @@ export interface LDDataSystemOptions {
6868

6969
/**
7070
* A component that obtains feature flag data and puts it in the feature store. Setting
71-
* this supercedes {@link LDDataSystemOptions#dataSource}.
71+
* this supersedes {@link LDDataSystemOptions#dataSource}.
7272
*/
7373
updateProcessor?:
7474
| object

packages/shared/sdk-server/src/api/options/LDOptions.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export interface LDOptions {
8383
* Configuration options for the Data System that the SDK uses to get and maintain flags and other
8484
* data from LaunchDarkly and other sources.
8585
*
86-
* Setting this option supercedes
86+
* Setting this option supersedes
8787
*
8888
* Example (Recommended):
8989
* ```typescript
@@ -127,9 +127,6 @@ export interface LDOptions {
127127
* A component that obtains feature flag data and puts it in the feature store.
128128
*
129129
* If you specify the {@link LDOptions#dataSystem}, this setting will be ignored.
130-
*
131-
* @deprecated This has moved to {@link LDOptions#dataSystem}. Use property
132-
* {@link LDDataSystemOptions#updateProcessor} instead.
133130
*/
134131
updateProcessor?:
135132
| object
@@ -149,10 +146,6 @@ export interface LDOptions {
149146
* The time between polling requests, in seconds. Ignored in streaming mode.
150147
*
151148
* If you specify the {@link LDOptions#dataSystem}, this setting will be ignored.
152-
*
153-
* @deprecated This functionality is now controlled by {@link LDOptions#dataSystem} by
154-
* specifying the {@link LDDataSystemOptions#dataSource}. Specifying the polling interval is still
155-
* available when using {@link StandardDataSourceOptions} or {@link PollingDataSourceOptions}.
156149
*/
157150
pollInterval?: number;
158151

@@ -220,7 +213,7 @@ export interface LDOptions {
220213
sendEvents?: boolean;
221214

222215
/**
223-
* Whether all context attributes (except the contexy key) should be marked as private, and
216+
* Whether all context attributes (except the context key) should be marked as private, and
224217
* not sent to LaunchDarkly.
225218
*
226219
* By default, this is false.

packages/shared/sdk-server/src/diagnostics/createDiagnosticsInitConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const createDiagnosticsInitConfig = (
4343
diagnosticRecordingIntervalMillis: secondsToMillis(config.diagnosticRecordingInterval),
4444

4545
streamingDisabled: isPollingOnlyOptions(config.dataSystem.dataSource),
46-
usingRelayDaemon: config.useLdd,
46+
usingRelayDaemon: config.dataSystem.useLdd,
4747
offline: config.offline,
4848
allAttributesPrivate: config.allAttributesPrivate,
4949
contextKeysCapacity: config.contextKeysCapacity,

packages/shared/sdk-server/src/options/Configuration.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,6 @@ export default class Configuration {
299299

300300
public readonly offline: boolean;
301301

302-
public readonly useLdd: boolean;
303-
304302
public readonly sendEvents: boolean;
305303

306304
public readonly allAttributesPrivate: boolean;
@@ -447,6 +445,5 @@ Type '((LDFeatureStore | ((options: LDOptions) => LDFeatureStore)) & ((...args:
447445
this.hooks = validatedOptions.hooks;
448446

449447
this.offline = validatedOptions.offline;
450-
this.useLdd = validatedOptions.useLdd;
451448
}
452449
}

packages/shared/sdk-server/src/options/ValidatedOptions.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export interface ValidatedOptions {
2323
flushInterval: number;
2424
pollInterval: number;
2525
offline: boolean;
26-
useLdd: boolean;
2726
allAttributesPrivate: false;
2827
privateAttributes: string[];
2928
contextKeysCapacity: number;

0 commit comments

Comments
 (0)