Skip to content

[FSSDK-8993]feat: switch odp event rest endpoint #808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 37 additions & 8 deletions packages/optimizely-sdk/lib/core/odp/odp_event_api_manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022, Optimizely
* Copyright 2022-2023, Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,7 +16,9 @@

import { LogHandler, LogLevel } from '../../modules/logging';
import { OdpEvent } from './odp_event';
import { isBrowserContext } from './odp_utils';
import { RequestHandler } from '../../utils/http_request_handler/http';
import { ODP_EVENT_BROWSER_ENDPOINT } from '../../utils/enums';

const EVENT_SENDING_FAILURE_MESSAGE = 'ODP event send failed';

Expand All @@ -33,6 +35,7 @@ export interface IOdpEventApiManager {
export class OdpEventApiManager implements IOdpEventApiManager {
private readonly logger: LogHandler;
private readonly requestHandler: RequestHandler;
private readonly isBrowser: boolean;

/**
* Creates instance to access Optimizely Data Platform (ODP) REST API
Expand All @@ -42,6 +45,7 @@ export class OdpEventApiManager implements IOdpEventApiManager {
constructor(requestHandler: RequestHandler, logger: LogHandler) {
this.requestHandler = requestHandler;
this.logger = logger;
this.isBrowser = isBrowserContext()
}

/**
Expand All @@ -64,14 +68,39 @@ export class OdpEventApiManager implements IOdpEventApiManager {
return shouldRetry;
}

const endpoint = `${apiHost}/v3/events`;
const data = JSON.stringify(events, this.replacer);
if (events.length > 1 && this.isBrowser) {
this.logger.log(LogLevel.ERROR, `${EVENT_SENDING_FAILURE_MESSAGE} (browser only supports batch size 1)`);
return shouldRetry;
}

let method, endpoint, headers, data;

if (this.isBrowser) {
method = 'GET';
const event = events[0];
const url = new URL(ODP_EVENT_BROWSER_ENDPOINT);
event.identifiers.forEach((v, k) =>{
url.searchParams.append(k, v);
});
event.data.forEach((v, k) =>{
url.searchParams.append(k, v as string);
});
url.searchParams.append('tracker_id', apiKey);
url.searchParams.append('event_type', event.type);
url.searchParams.append('vdl_action', event.action);
endpoint = url.toString();
headers = {};
} else {
method = 'POST';
endpoint = `${apiHost}/v3/events`;
headers = {
'Content-Type': 'application/json',
'x-api-key': apiKey,
};
data = JSON.stringify(events, this.replacer);
}


const method = 'POST';
const headers = {
'Content-Type': 'application/json',
'x-api-key': apiKey,
};

let statusCode = 0;
try {
Expand Down
49 changes: 24 additions & 25 deletions packages/optimizely-sdk/lib/core/odp/odp_event_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { ERROR_MESSAGES, ODP_USER_KEY, ODP_DEFAULT_EVENT_TYPE, ODP_EVENT_ACTION
import { OdpEvent } from './odp_event';
import { OdpConfig } from './odp_config';
import { OdpEventApiManager } from './odp_event_api_manager';
import { invalidOdpDataFound } from './odp_utils';
import { invalidOdpDataFound, isBrowserContext } from './odp_utils';

const MAX_RETRIES = 3;
const DEFAULT_BATCH_SIZE = 10;
Expand Down Expand Up @@ -54,6 +54,8 @@ export interface IOdpEventManager {
identifyUser(userId: string, vuid?: string): void;

sendEvent(event: OdpEvent): void;

flush(): void;
}

/**
Expand Down Expand Up @@ -95,12 +97,12 @@ export class OdpEventManager implements IOdpEventManager {
*/
private readonly queueSize: number;
/**
* Maximum number of events to process at once
* Maximum number of events to process at once. Ignored in browser context
* @private
*/
private readonly batchSize: number;
/**
* Milliseconds between setTimeout() to process new batches
* Milliseconds between setTimeout() to process new batches. Ignored in browser context
* @private
*/
private readonly flushInterval: number;
Expand Down Expand Up @@ -140,27 +142,29 @@ export class OdpEventManager implements IOdpEventManager {
this.clientEngine = clientEngine;
this.clientVersion = clientVersion;

let defaultQueueSize = DEFAULT_BROWSER_QUEUE_SIZE;

try {
// TODO: Consider refactoring to use typeof process and combine w/above line
if (process) {
defaultQueueSize = DEFAULT_SERVER_QUEUE_SIZE;
}
} catch (e) {
// TODO: Create Browser and Non-Browser specific variants of ODP Event Manager to avoid this try/catch
}
const isBrowser = isBrowserContext();

const defaultQueueSize = isBrowser ? DEFAULT_BROWSER_QUEUE_SIZE : DEFAULT_SERVER_QUEUE_SIZE;
this.queueSize = queueSize || defaultQueueSize;
this.batchSize = batchSize || DEFAULT_BATCH_SIZE;
if (flushInterval === 0) {

if (flushInterval === 0 || isBrowser) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Thoughts on leaving a comment here and/or in OdpOptions to denote certain odpOptions (queueSize, batchSize, flushInterval) will always be overridden in the browser context?

// disable event batching
this.batchSize = 1;
this.flushInterval = 0;
} else {
this.flushInterval = flushInterval || DEFAULT_FLUSH_INTERVAL_MSECS;
}

if (isBrowser) {
if (typeof batchSize !== 'undefined' && batchSize !== 1) {
this.logger.log(LogLevel.WARNING, 'ODP event batch size must be 1 in the browser.');
}
if (typeof flushInterval !== 'undefined' && flushInterval !== 0) {
this.logger.log(LogLevel.WARNING, 'ODP event flush interval must be 0 in the browser.');
}
}

this.state = STATE.STOPPED;
}

Expand Down Expand Up @@ -398,17 +402,12 @@ export class OdpEventManager implements IOdpEventManager {
return true;
}

try {
if (process) {
// if Node/server-side context, empty queue items before ready state
this.logger.log(LogLevel.WARNING, 'ODPConfig not ready. Discarding events in queue.');
this.queue = new Array<OdpEvent>();
} else {
// in Browser/client-side context, give debug message but leave events in queue
this.logger.log(LogLevel.DEBUG, 'ODPConfig not ready. Leaving events in queue.');
}
} catch (e) {
// TODO: Create Browser and Non-Browser specific variants of ODP Event Manager to avoid this try/catch
if (!isBrowserContext()) {
// if Node/server-side context, empty queue items before ready state
this.logger.log(LogLevel.WARNING, 'ODPConfig not ready. Discarding events in queue.');
this.queue = new Array<OdpEvent>();
} else {
// in Browser/client-side context, give debug message but leave events in queue
this.logger.log(LogLevel.DEBUG, 'ODPConfig not ready. Leaving events in queue.');
}

Expand Down
11 changes: 11 additions & 0 deletions packages/optimizely-sdk/lib/core/odp/odp_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@ export function invalidOdpDataFound(data: Map<string, any>): boolean {
});
return foundInvalidValue;
}

/**
* Determine if the runtime environment is a browser
* @returns True if in the browser
* @private
*/
export function isBrowserContext(): boolean {
return !(typeof process !== "undefined" &&
process.versions != null &&
process.versions.node != null);
}
Loading