Skip to content

Commit 60bb87e

Browse files
committed
optimizely service
1 parent 51d882f commit 60bb87e

File tree

4 files changed

+75
-89
lines changed

4 files changed

+75
-89
lines changed

lib/optimizely/index.tests.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9254,9 +9254,9 @@ describe('lib/optimizely', function() {
92549254
});
92559255

92569256
it('returns a promise that fulfills with a successful result object', function() {
9257-
return optlyInstance.close().then(function(result) {
9258-
assert.deepEqual(result, { success: true });
9259-
});
9257+
return optlyInstance.close().then().catch(() => {
9258+
assert.fail();
9259+
})
92609260
});
92619261
});
92629262

@@ -9291,13 +9291,11 @@ describe('lib/optimizely', function() {
92919291
});
92929292
});
92939293

9294-
it('returns a promise that fulfills with an unsuccessful result object', function() {
9295-
return optlyInstance.close().then(function(result) {
9296-
// assert.deepEqual(result, {
9297-
// success: false,
9298-
// reason: 'Error: Failed to stop',
9299-
// });
9300-
assert.isFalse(result.success);
9294+
it('returns a promise that rejects', function() {
9295+
return optlyInstance.close().then(() => {
9296+
assert.fail('promnise should reject')
9297+
}).catch(() => {
9298+
93019299
});
93029300
});
93039301
});

lib/optimizely/index.ts

Lines changed: 65 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { OdpManager } from '../odp/odp_manager';
2222
import { VuidManager } from '../vuid/vuid_manager';
2323
import { OdpEvent } from '../odp/event_manager/odp_event';
2424
import { OptimizelySegmentOption } from '../odp/segment_manager/optimizely_segment_option';
25-
import { BaseService } from '../service';
25+
import { BaseService, ServiceState } from '../service';
2626

2727
import {
2828
UserAttributes,
@@ -43,7 +43,7 @@ import { ProjectConfigManager } from '../project_config/project_config_manager';
4343
import { createDecisionService, DecisionService, DecisionObj } from '../core/decision_service';
4444
import { buildLogEvent } from '../event_processor/event_builder/log_event';
4545
import { buildImpressionEvent, buildConversionEvent } from '../event_processor/event_builder/user_event';
46-
import fns from '../utils/fns';
46+
import { isSafeInteger } from '../utils/fns';
4747
import { validate } from '../utils/attributes_validator';
4848
import * as eventTagsValidator from '../utils/event_tags_validator';
4949
import * as projectConfig from '../project_config/project_config';
@@ -132,9 +132,7 @@ export type OptimizelyOptions = {
132132
disposable?: boolean;
133133
}
134134

135-
export default class Optimizely implements Client {
136-
private disposeOnUpdate?: Fn;
137-
private readyPromise: Promise<unknown>;
135+
export default class Optimizely extends BaseService implements Client {
138136
// readyTimeout is specified as any to make this work in both browser & Node
139137
// eslint-disable-next-line @typescript-eslint/no-explicit-any
140138
private readyTimeouts: { [key: string]: { readyTimeout: any; onClose: () => void } };
@@ -143,7 +141,6 @@ export default class Optimizely implements Client {
143141
private clientVersion: string;
144142
private errorNotifier?: ErrorNotifier;
145143
private errorReporter: ErrorReporter;
146-
protected logger?: LoggerFacade;
147144
private projectConfigManager: ProjectConfigManager;
148145
private decisionService: DecisionService;
149146
private eventProcessor?: EventProcessor;
@@ -153,6 +150,8 @@ export default class Optimizely implements Client {
153150
private vuidManager?: VuidManager;
154151

155152
constructor(config: OptimizelyOptions) {
153+
super();
154+
156155
let clientEngine = config.clientEngine;
157156
if (!clientEngine) {
158157
config.logger?.info(INVALID_CLIENT_ENGINE, clientEngine);
@@ -193,7 +192,8 @@ export default class Optimizely implements Client {
193192
});
194193
this.defaultDecideOptions = defaultDecideOptions;
195194

196-
this.disposeOnUpdate = this.projectConfigManager.onUpdate((configObj: projectConfig.ProjectConfig) => {
195+
this.projectConfigManager = config.projectConfigManager;
196+
this.projectConfigManager.onUpdate((configObj: projectConfig.ProjectConfig) => {
197197
this.logger?.info(
198198
UPDATED_OPTIMIZELY_CONFIG,
199199
configObj.revision,
@@ -205,9 +205,14 @@ export default class Optimizely implements Client {
205205
this.updateOdpSettings();
206206
});
207207

208-
this.projectConfigManager.start();
209-
const projectConfigManagerRunningPromise = this.projectConfigManager.onRunning();
208+
this.eventProcessor = config.eventProcessor;
209+
this.eventProcessor?.onDispatch((event) => {
210+
this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.LOG_EVENT, event);
211+
});
212+
213+
this.odpManager = config.odpManager;
210214

215+
211216
let userProfileService: UserProfileService | null = null;
212217
if (config.userProfileService) {
213218
try {
@@ -228,36 +233,38 @@ export default class Optimizely implements Client {
228233

229234
this.notificationCenter = createNotificationCenter({ logger: this.logger, errorNotifier: this.errorNotifier });
230235

231-
this.eventProcessor = config.eventProcessor;
236+
this.readyTimeouts = {};
237+
this.nextReadyTimeoutId = 0;
232238

233-
this.eventProcessor?.start();
234-
const eventProcessorRunningPromise = this.eventProcessor ? this.eventProcessor.onRunning() :
235-
Promise.resolve(undefined);
239+
this.start();
240+
}
236241

237-
this.eventProcessor?.onDispatch((event) => {
238-
this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.LOG_EVENT, event);
239-
});
242+
start(): void {
243+
super.start();
240244

245+
this.state = ServiceState.Starting;
246+
this.projectConfigManager.start();
247+
this.eventProcessor?.start();
241248
this.odpManager?.start();
242249

243-
this.readyPromise = Promise.all([
244-
projectConfigManagerRunningPromise,
245-
eventProcessorRunningPromise,
246-
config.odpManager ? config.odpManager.onRunning() : Promise.resolve(),
247-
config.vuidManager ? config.vuidManager.initialize() : Promise.resolve(),
248-
]);
250+
Promise.all([
251+
this.projectConfigManager.onRunning(),
252+
this.eventProcessor ? this.eventProcessor.onRunning() : Promise.resolve(),
253+
this.odpManager ? this.odpManager.onRunning() : Promise.resolve(),
254+
this.vuidManager ? this.vuidManager.initialize() : Promise.resolve(),
255+
]).then(() => {
256+
this.state = ServiceState.Running;
257+
this.startPromise.resolve();
249258

250-
this.readyPromise.then(() => {
251259
const vuid = this.vuidManager?.getVuid();
252260
if (vuid) {
253261
this.odpManager?.setVuid(vuid);
254262
}
255263
});
256-
257-
this.readyTimeouts = {};
258-
this.nextReadyTimeoutId = 0;
259264
}
260265

266+
267+
261268
/**
262269
* Returns the project configuration retrieved from projectConfigManager
263270
* @return {projectConfig.ProjectConfig}
@@ -1228,62 +1235,43 @@ export default class Optimizely implements Client {
12281235
* above) are complete. If there are no in-flight event dispatcher requests and
12291236
* no queued events waiting to be sent, returns an immediately-fulfilled Promise.
12301237
*
1231-
* Returned Promises are fulfilled with result objects containing these
1232-
* properties:
1233-
* - success (boolean): true if the event dispatcher signaled completion of
1234-
* all in-flight and final requests, or if there were no
1235-
* queued events and no in-flight requests. false if an
1236-
* unexpected error was encountered during the close
1237-
* process.
1238-
* - reason (string=): If success is false, this is a string property with
1239-
* an explanatory message.
12401238
*
12411239
* NOTE: After close is called, this instance is no longer usable - any events
12421240
* generated will no longer be sent to the event dispatcher.
12431241
*
12441242
* @return {Promise}
12451243
*/
1246-
close(): Promise<{ success: boolean; reason?: string }> {
1247-
try {
1248-
this.projectConfigManager.stop();
1249-
this.eventProcessor?.stop();
1250-
this.odpManager?.stop();
1251-
this.notificationCenter.clearAllNotificationListeners();
1252-
1253-
const eventProcessorStoppedPromise = this.eventProcessor ? this.eventProcessor.onTerminated() :
1254-
Promise.resolve();
1255-
1256-
if (this.disposeOnUpdate) {
1257-
this.disposeOnUpdate();
1258-
this.disposeOnUpdate = undefined;
1259-
}
1244+
close(): Promise<unknown> {
1245+
this.stop();
1246+
return this.onTerminated();
1247+
}
12601248

1261-
Object.keys(this.readyTimeouts).forEach((readyTimeoutId: string) => {
1262-
const readyTimeoutRecord = this.readyTimeouts[readyTimeoutId];
1263-
clearTimeout(readyTimeoutRecord.readyTimeout);
1264-
readyTimeoutRecord.onClose();
1265-
});
1266-
this.readyTimeouts = {};
1267-
return eventProcessorStoppedPromise.then(
1268-
function() {
1269-
return {
1270-
success: true,
1271-
};
1272-
},
1273-
function(err) {
1274-
return {
1275-
success: false,
1276-
reason: String(err),
1277-
};
1278-
}
1279-
);
1280-
} catch (err) {
1249+
stop(): void {
1250+
this.state = ServiceState.Stopping;
1251+
1252+
this.projectConfigManager.stop();
1253+
this.eventProcessor?.stop();
1254+
this.odpManager?.stop();
1255+
this.notificationCenter.clearAllNotificationListeners();
1256+
1257+
Object.keys(this.readyTimeouts).forEach((readyTimeoutId: string) => {
1258+
const readyTimeoutRecord = this.readyTimeouts[readyTimeoutId];
1259+
clearTimeout(readyTimeoutRecord.readyTimeout);
1260+
readyTimeoutRecord.onClose();
1261+
});
1262+
1263+
Promise.all([
1264+
this.projectConfigManager.onTerminated(),
1265+
this.eventProcessor ? this.eventProcessor.onTerminated() : Promise.resolve(),
1266+
this.odpManager ? this.odpManager.onTerminated() : Promise.resolve(),
1267+
]).then(() => {
1268+
this.state = ServiceState.Terminated;
1269+
this.stopPromise.resolve()
1270+
}).catch((err) => {
12811271
this.errorReporter.report(err);
1282-
return Promise.resolve({
1283-
success: false,
1284-
reason: String(err),
1285-
});
1286-
}
1272+
this.state = ServiceState.Failed;
1273+
this.stopPromise.reject(err);
1274+
});
12871275
}
12881276

12891277
/**
@@ -1320,7 +1308,7 @@ export default class Optimizely implements Client {
13201308
timeoutValue = options.timeout;
13211309
}
13221310
}
1323-
if (!fns.isSafeInteger(timeoutValue)) {
1311+
if (!isSafeInteger(timeoutValue)) {
13241312
timeoutValue = DEFAULT_ONREADY_TIMEOUT;
13251313
}
13261314

@@ -1343,12 +1331,12 @@ export default class Optimizely implements Client {
13431331
onClose: onClose,
13441332
};
13451333

1346-
this.readyPromise.then(() => {
1334+
this.onRunning().then(() => {
13471335
clearTimeout(readyTimeout);
13481336
delete this.readyTimeouts[timeoutId];
13491337
});
13501338

1351-
return Promise.race([this.readyPromise, timeoutPromise]);
1339+
return Promise.race([this.onRunning(), timeoutPromise]);
13521340
}
13531341

13541342
//============ decide ============//

lib/shared_types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ export interface Client {
319319
): { [variableKey: string]: unknown } | null;
320320
getOptimizelyConfig(): OptimizelyConfig | null;
321321
onReady(options?: { timeout?: number }): Promise<unknown>;
322-
close(): Promise<{ success: boolean; reason?: string }>;
322+
close(): Promise<unknown>;
323323
sendOdpEvent(action: string, type?: string, identifiers?: Map<string, string>, data?: Map<string, unknown>): void;
324324
getProjectConfig(): ProjectConfig | null;
325325
isOdpIntegrated(): boolean;

lib/utils/fns/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function currentTimestamp(): number {
2121
return Math.round(new Date().getTime());
2222
}
2323

24-
function isSafeInteger(number: unknown): boolean {
24+
export function isSafeInteger(number: unknown): boolean {
2525
return typeof number == 'number' && Math.abs(number) <= MAX_SAFE_INTEGER_LIMIT;
2626
}
2727

0 commit comments

Comments
 (0)