Skip to content

Commit 446d8f2

Browse files
committed
optimizely service
1 parent bc49e3c commit 446d8f2

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}
@@ -1220,62 +1227,43 @@ export default class Optimizely implements Client {
12201227
* above) are complete. If there are no in-flight event dispatcher requests and
12211228
* no queued events waiting to be sent, returns an immediately-fulfilled Promise.
12221229
*
1223-
* Returned Promises are fulfilled with result objects containing these
1224-
* properties:
1225-
* - success (boolean): true if the event dispatcher signaled completion of
1226-
* all in-flight and final requests, or if there were no
1227-
* queued events and no in-flight requests. false if an
1228-
* unexpected error was encountered during the close
1229-
* process.
1230-
* - reason (string=): If success is false, this is a string property with
1231-
* an explanatory message.
12321230
*
12331231
* NOTE: After close is called, this instance is no longer usable - any events
12341232
* generated will no longer be sent to the event dispatcher.
12351233
*
12361234
* @return {Promise}
12371235
*/
1238-
close(): Promise<{ success: boolean; reason?: string }> {
1239-
try {
1240-
this.projectConfigManager.stop();
1241-
this.eventProcessor?.stop();
1242-
this.odpManager?.stop();
1243-
this.notificationCenter.clearAllNotificationListeners();
1244-
1245-
const eventProcessorStoppedPromise = this.eventProcessor ? this.eventProcessor.onTerminated() :
1246-
Promise.resolve();
1247-
1248-
if (this.disposeOnUpdate) {
1249-
this.disposeOnUpdate();
1250-
this.disposeOnUpdate = undefined;
1251-
}
1236+
close(): Promise<unknown> {
1237+
this.stop();
1238+
return this.onTerminated();
1239+
}
12521240

1253-
Object.keys(this.readyTimeouts).forEach((readyTimeoutId: string) => {
1254-
const readyTimeoutRecord = this.readyTimeouts[readyTimeoutId];
1255-
clearTimeout(readyTimeoutRecord.readyTimeout);
1256-
readyTimeoutRecord.onClose();
1257-
});
1258-
this.readyTimeouts = {};
1259-
return eventProcessorStoppedPromise.then(
1260-
function() {
1261-
return {
1262-
success: true,
1263-
};
1264-
},
1265-
function(err) {
1266-
return {
1267-
success: false,
1268-
reason: String(err),
1269-
};
1270-
}
1271-
);
1272-
} catch (err) {
1241+
stop(): void {
1242+
this.state = ServiceState.Stopping;
1243+
1244+
this.projectConfigManager.stop();
1245+
this.eventProcessor?.stop();
1246+
this.odpManager?.stop();
1247+
this.notificationCenter.clearAllNotificationListeners();
1248+
1249+
Object.keys(this.readyTimeouts).forEach((readyTimeoutId: string) => {
1250+
const readyTimeoutRecord = this.readyTimeouts[readyTimeoutId];
1251+
clearTimeout(readyTimeoutRecord.readyTimeout);
1252+
readyTimeoutRecord.onClose();
1253+
});
1254+
1255+
Promise.all([
1256+
this.projectConfigManager.onTerminated(),
1257+
this.eventProcessor ? this.eventProcessor.onTerminated() : Promise.resolve(),
1258+
this.odpManager ? this.odpManager.onTerminated() : Promise.resolve(),
1259+
]).then(() => {
1260+
this.state = ServiceState.Terminated;
1261+
this.stopPromise.resolve()
1262+
}).catch((err) => {
12731263
this.errorReporter.report(err);
1274-
return Promise.resolve({
1275-
success: false,
1276-
reason: String(err),
1277-
});
1278-
}
1264+
this.state = ServiceState.Failed;
1265+
this.stopPromise.reject(err);
1266+
});
12791267
}
12801268

12811269
/**
@@ -1312,7 +1300,7 @@ export default class Optimizely implements Client {
13121300
timeoutValue = options.timeout;
13131301
}
13141302
}
1315-
if (!fns.isSafeInteger(timeoutValue)) {
1303+
if (!isSafeInteger(timeoutValue)) {
13161304
timeoutValue = DEFAULT_ONREADY_TIMEOUT;
13171305
}
13181306

@@ -1335,12 +1323,12 @@ export default class Optimizely implements Client {
13351323
onClose: onClose,
13361324
};
13371325

1338-
this.readyPromise.then(() => {
1326+
this.onRunning().then(() => {
13391327
clearTimeout(readyTimeout);
13401328
delete this.readyTimeouts[timeoutId];
13411329
});
13421330

1343-
return Promise.race([this.readyPromise, timeoutPromise]);
1331+
return Promise.race([this.onRunning(), timeoutPromise]);
13441332
}
13451333

13461334
//============ 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)