Skip to content

Commit ea9845d

Browse files
committed
Addressing review comments
1 parent 6d0a08b commit ea9845d

File tree

3 files changed

+20
-18
lines changed

3 files changed

+20
-18
lines changed

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
CompositeDataSource,
3-
Transition,
43
TransitionConditions,
54
} from '../../../src/api/subsystem/DataSystem/CompositeDataSource';
65
import {
@@ -57,7 +56,7 @@ function makeZeroBackoff(): Backoff {
5756
};
5857
}
5958

60-
it('initializer gets basis, switch to syncrhonizer', async () => {
59+
it('handles initializer getting basis, switching to syncrhonizer', async () => {
6160
const mockInitializer1 = {
6261
run: jest
6362
.fn()
@@ -112,7 +111,7 @@ it('initializer gets basis, switch to syncrhonizer', async () => {
112111
expect(callback).toHaveBeenNthCalledWith(2, false, { key: 'sync1' });
113112
});
114113

115-
it('initializer gets basis, switch to synchronizer 1, fallback to synchronizer 2, recover to synchronizer 1', async () => {
114+
it('handles initializer getting basis, switches to synchronizer 1, falls back to synchronizer 2, recovers to synchronizer 1', async () => {
116115
const mockInitializer1: DataSystemInitializer = {
117116
run: jest
118117
.fn()
@@ -194,7 +193,7 @@ it('initializer gets basis, switch to synchronizer 1, fallback to synchronizer 2
194193
expect(callback).toHaveBeenNthCalledWith(3, false, { key: 'sync1' }); // sync2 recovers back to sync1
195194
});
196195

197-
it('it reports error when all initializers fail', async () => {
196+
it('reports error when all initializers fail', async () => {
198197
const mockInitializer1Error = {
199198
name: 'Error',
200199
message: 'I am initializer1 error!',
@@ -271,7 +270,7 @@ it('it reports error when all initializers fail', async () => {
271270
expect(statusCallback).toHaveBeenCalledTimes(3);
272271
});
273272

274-
it('it can be stopped when in thrashing synchronizer fallback loop', async () => {
273+
it('can be stopped when in thrashing synchronizer fallback loop', async () => {
275274
const mockInitializer1 = {
276275
run: jest
277276
.fn()
@@ -338,7 +337,7 @@ it('it can be stopped when in thrashing synchronizer fallback loop', async () =>
338337
expect(statusCallback).toHaveBeenNthCalledWith(2, DataSourceState.Closed, undefined);
339338
});
340339

341-
it('it can be stopped and restarted', async () => {
340+
it('can be stopped and restarted', async () => {
342341
const mockInitializer1Data = { key: 'init1' };
343342
const mockInitializer1 = {
344343
run: jest
@@ -415,7 +414,7 @@ it('it can be stopped and restarted', async () => {
415414
expect(callback2).toHaveBeenCalledTimes(2);
416415
});
417416

418-
it('it is well behaved with no initializers and no synchronizers configured', async () => {
417+
it('is well behaved with no initializers and no synchronizers configured', async () => {
419418
const underTest = new CompositeDataSource(
420419
[],
421420
[],
@@ -439,7 +438,7 @@ it('it is well behaved with no initializers and no synchronizers configured', as
439438
});
440439
});
441440

442-
it('it is well behaved with an initializer and no synchronizers configured', async () => {
441+
it('is well behaved with an initializer and no synchronizers configured', async () => {
443442
const mockInitializer1 = {
444443
run: jest
445444
.fn()

packages/shared/common/src/api/subsystem/DataSystem/CallbackHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class CallbackHandler {
1717
this._disabled = true;
1818
}
1919

20-
async dataHanlder(basis: boolean, data: Data) {
20+
async dataHandler(basis: boolean, data: Data) {
2121
if (this._disabled) {
2222
return;
2323
}

packages/shared/common/src/api/subsystem/DataSystem/CompositeDataSource.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable no-await-in-loop */
22
import { Backoff } from '../../../datasource/Backoff';
3+
import { LDLogger } from '../../logging';
34
import { CallbackHandler } from './CallbackHandler';
45
import {
56
Data,
@@ -46,6 +47,7 @@ export class CompositeDataSource implements DataSource {
4647
private _stopped: boolean = true;
4748
private _externalTransitionPromise: Promise<TransitionRequest>;
4849
private _externalTransitionResolve?: (value: TransitionRequest) => void;
50+
private _cancelTokens: (() => void)[] = [];
4951

5052
/**
5153
* @param _initializers factories to create {@link DataSystemInitializer}s, in priority order.
@@ -56,6 +58,7 @@ export class CompositeDataSource implements DataSource {
5658
private readonly _synchronizers: SynchronizerFactory[],
5759
private readonly _transitionConditions: TransitionConditions,
5860
private readonly _backoff: Backoff,
61+
private readonly _logger?: LDLogger,
5962
) {
6063
this._externalTransitionPromise = new Promise<TransitionRequest>((resolveTransition) => {
6164
this._externalTransitionResolve = resolveTransition;
@@ -70,6 +73,7 @@ export class CompositeDataSource implements DataSource {
7073
): Promise<void> {
7174
if (!this._stopped) {
7275
// don't allow multiple simultaneous runs
76+
this._logger?.info('CompositeDataSource already running. Ignoring call to start.');
7377
return;
7478
}
7579
this._stopped = false;
@@ -116,6 +120,7 @@ export class CompositeDataSource implements DataSource {
116120
const condition = this._lookupTransitionCondition(state, excludeRecovery);
117121
if (condition) {
118122
const { promise, cancel } = this._cancellableDelay(condition.durationMS);
123+
this._cancelTokens.push(cancel);
119124
cancelScheduledTransition = cancel;
120125
promise.then(() => {
121126
callbackHandler.disable();
@@ -129,7 +134,7 @@ export class CompositeDataSource implements DataSource {
129134
},
130135
);
131136
currentDS.run(
132-
(basis, data) => callbackHandler.dataHanlder(basis, data),
137+
(basis, data) => callbackHandler.dataHandler(basis, data),
133138
(status, err) => callbackHandler.statusHandler(status, err),
134139
);
135140
} else {
@@ -156,9 +161,9 @@ export class CompositeDataSource implements DataSource {
156161
if (transitionRequest.err && transitionRequest.transition !== 'stop') {
157162
// if the transition was due to an error, throttle the transition
158163
const delay = this._backoff.fail();
159-
const delayedTransition = new Promise((resolve) => {
160-
setTimeout(resolve, delay);
161-
}).then(() => transitionRequest);
164+
const { promise, cancel } = this._cancellableDelay(delay);
165+
this._cancelTokens.push(cancel);
166+
const delayedTransition = promise.then(() => transitionRequest);
162167

163168
// race the delayed transition and external transition requests to be responsive
164169
transitionRequest = await Promise.race([
@@ -170,6 +175,7 @@ export class CompositeDataSource implements DataSource {
170175
if (transitionRequest.transition === 'stop') {
171176
// exit the loop
172177
statusCallback(DataSourceState.Closed, transitionRequest.err);
178+
lastTransition = transitionRequest.transition;
173179
break;
174180
}
175181

@@ -181,6 +187,7 @@ export class CompositeDataSource implements DataSource {
181187
}
182188

183189
async stop() {
190+
this._cancelTokens.forEach((cancel) => cancel());
184191
this._externalTransitionResolve?.({ transition: 'stop' });
185192
}
186193

@@ -254,19 +261,15 @@ export class CompositeDataSource implements DataSource {
254261

255262
private _cancellableDelay = (delayMS: number) => {
256263
let timeout: ReturnType<typeof setTimeout> | undefined;
257-
let reject: ((reason?: any) => void) | undefined;
258-
const promise = new Promise((res, rej) => {
264+
const promise = new Promise((res, _) => {
259265
timeout = setTimeout(res, delayMS);
260-
reject = rej;
261266
});
262267
return {
263268
promise,
264269
cancel() {
265270
if (timeout) {
266271
clearTimeout(timeout);
267-
reject?.();
268272
timeout = undefined;
269-
reject = undefined;
270273
}
271274
},
272275
};

0 commit comments

Comments
 (0)