Skip to content
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
3 changes: 2 additions & 1 deletion src/listeners/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ISettings } from '../types';
import SplitIO from '../../types/splitio';
import { ImpressionsPayload } from '../sync/submitters/types';
import { objectAssign } from '../utils/lang/objectAssign';
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING, SUBMITTERS_PUSH_PAGE_HIDDEN } from '../logger/constants';
import { ISyncManager } from '../sync/types';
import { isConsentGranted } from '../consent';

Expand Down Expand Up @@ -104,6 +104,7 @@ export class BrowserSignalListener implements ISignalListener {
if (!this._sendBeacon(url, dataPayload, extraMetadata)) {
postService(JSON.stringify(dataPayload)).catch(() => { }); // no-op to handle possible promise rejection
}
this.settings.log.debug(SUBMITTERS_PUSH_PAGE_HIDDEN, [cache.name]);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/logger/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const IMPRESSIONS_TRACKER_SUCCESS = 121;
export const USER_CONSENT_UPDATED = 122;
export const USER_CONSENT_NOT_UPDATED = 123;
export const USER_CONSENT_INITIAL = 124;
export const SUBMITTERS_PUSH_PAGE_HIDDEN = 125;

export const ENGINE_VALUE_INVALID = 200;
export const ENGINE_VALUE_NO_ATTRIBUTES = 201;
Expand Down
1 change: 1 addition & 0 deletions src/logger/messages/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const codesInfo: [number, string][] = codesWarn.concat([
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying download of feature flags #%s. Reason: %s'],
[c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and resetting timer.'],
[c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s.'],
[c.SUBMITTERS_PUSH_PAGE_HIDDEN, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing %s because page became hidden.'],
[c.STREAMING_REFRESH_TOKEN, c.LOG_PREFIX_SYNC_STREAMING + 'Refreshing streaming token in %s seconds, and connecting streaming in %s seconds.'],
[c.STREAMING_RECONNECT, c.LOG_PREFIX_SYNC_STREAMING + 'Attempting to reconnect streaming in %s seconds.'],
[c.STREAMING_CONNECTING, c.LOG_PREFIX_SYNC_STREAMING + 'Connecting streaming.'],
Expand Down
1 change: 1 addition & 0 deletions src/storages/inMemory/EventsCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const MAX_QUEUE_BYTE_SIZE = 5 * 1024 * 1024; // 5M

export class EventsCacheInMemory implements IEventsCacheSync {

public name = 'events';
private onFullQueue?: () => void;
private readonly maxQueue: number;
private queue: SplitIO.EventData[];
Expand Down
2 changes: 2 additions & 0 deletions src/storages/inMemory/ImpressionCountsCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
import { IImpressionCountsCacheSync } from '../types';

export class ImpressionCountsCacheInMemory implements IImpressionCountsCacheSync {

public name = 'impression counts';
protected cache: Record<string, number> = {};
private readonly maxStorage: number;
protected onFullQueue?: () => void;
Expand Down
1 change: 1 addition & 0 deletions src/storages/inMemory/ImpressionsCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SplitIO from '../../../types/splitio';

export class ImpressionsCacheInMemory implements IImpressionsCacheSync {

public name = 'impressions';
private onFullQueue?: () => void;
private readonly maxQueue: number;
private queue: SplitIO.ImpressionDTO[];
Expand Down
2 changes: 2 additions & 0 deletions src/storages/inMemory/TelemetryCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export function shouldRecordTelemetry({ settings }: IStorageFactoryParams) {

export class TelemetryCacheInMemory implements ITelemetryCacheSync {

public name = 'telemetry stats';

constructor(private splits?: ISplitsCacheSync, private segments?: ISegmentsCacheSync, private largeSegments?: ISegmentsCacheSync) { }

// isEmpty flag
Expand Down
6 changes: 3 additions & 3 deletions src/storages/inMemory/UniqueKeysCacheInMemory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IUniqueKeysCacheBase } from '../types';
import { IUniqueKeysCacheSync } from '../types';
import { UniqueKeysPayloadSs } from '../../sync/submitters/types';
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
import { setToArray } from '../../utils/lang/sets';
Expand All @@ -22,8 +22,8 @@ export function fromUniqueKeysCollector(uniqueKeys: { [featureName: string]: Set
return { keys: payload };
}

export class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {

export class UniqueKeysCacheInMemory implements IUniqueKeysCacheSync {
public name = 'unique keys';
protected onFullQueue?: () => void;
private readonly maxStorage: number;
private uniqueTrackerSize = 0;
Expand Down
6 changes: 3 additions & 3 deletions src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { IUniqueKeysCacheBase } from '../types';
import { IUniqueKeysCacheSync } from '../types';
import { UniqueKeysPayloadCs } from '../../sync/submitters/types';
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
import { setToArray } from '../../utils/lang/sets';

export class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {

export class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheSync {
public name = 'unique keys';
private onFullQueue?: () => void;
private readonly maxStorage: number;
private uniqueTrackerSize = 0;
Expand Down
1 change: 1 addition & 0 deletions src/storages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export interface IUniqueKeysCacheBase {

// API methods for sync recorder storages, used by submitters in standalone mode to pop data and post it to Split BE.
export interface IRecorderCacheSync<T> {
name: string,
// @TODO names are inconsistent with spec
/* Checks if cache is empty. Returns true if the cache was just created or cleared */
isEmpty(): boolean
Expand Down
6 changes: 2 additions & 4 deletions src/sync/submitters/eventsSubmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { submitterFactory, firstPushWindowDecorator } from './submitter';
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
import { ISdkFactoryContextSync } from '../../sdkFactory/types';

const DATA_NAME = 'events';

/**
* Submitter that periodically posts tracked events
*/
Expand All @@ -16,15 +14,15 @@ export function eventsSubmitterFactory(params: ISdkFactoryContextSync) {
} = params;

// don't retry events.
let submitter = submitterFactory(log, postEventsBulk, events, eventsPushRate, DATA_NAME);
let submitter = submitterFactory(log, postEventsBulk, events, eventsPushRate);

// Set a timer for the first push window of events.
if (eventsFirstPushWindow > 0) submitter = firstPushWindowDecorator(submitter, eventsFirstPushWindow);

// register events submitter to be executed when events cache is full
events.setOnFullQueueCb(() => {
if (submitter.isRunning()) {
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [events.name]);
submitter.execute();
}
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
Expand Down
2 changes: 1 addition & 1 deletion src/sync/submitters/impressionCountsSubmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ export function impressionCountsSubmitterFactory(params: ISdkFactoryContextSync)
} = params;

// retry impressions counts only once.
return submitterFactory(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
return submitterFactory(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, fromImpressionCountsCollector, 1);
}
7 changes: 2 additions & 5 deletions src/sync/submitters/impressionsSubmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@ import { ImpressionsPayload } from './types';
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
import { ISdkFactoryContextSync } from '../../sdkFactory/types';

const DATA_NAME = 'impressions';

/**
* Converts `impressions` data from cache into request payload.
*/
export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
let groupedByFeature = groupBy(data, 'feature');
let dto: ImpressionsPayload = [];

// using forOwn instead of for...in since the last also iterates over prototype enumerables
forOwn(groupedByFeature, (value, name) => {
dto.push({
f: name, // Test Name
Expand Down Expand Up @@ -50,12 +47,12 @@ export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) {
} = params;

// retry impressions only once.
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, DATA_NAME, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);

// register impressions submitter to be executed when impressions cache is full
impressions.setOnFullQueueCb(() => {
if (syncTask.isRunning()) {
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [impressions.name]);
syncTask.execute();
}
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
Expand Down
2 changes: 1 addition & 1 deletion src/sync/submitters/submitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ export function submitterFactory<T>(
postClient: (body: string) => Promise<IResponse>,
sourceCache: IRecorderCacheSync<T>,
postRate: number,
dataName: string,
fromCacheToPayload?: (cacheData: T) => any,
maxRetries: number = 0,
debugLogs?: boolean // true for telemetry submitters
): ISyncTask<[], void> {

const dataName = sourceCache.name;
let retries = 0;
let data: any;

Expand Down
5 changes: 3 additions & 2 deletions src/sync/submitters/telemetrySubmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export function getTelemetryConfigStats(mode: SplitIO.SDKMode, storageType: stri
*/
export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, settings: ISettings) {
return {
name: 'telemetry config',
isEmpty() { return false; },
clear() { },

Expand Down Expand Up @@ -124,7 +125,7 @@ export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
submitterFactory(
log, splitApi.postMetricsUsage,
telemetry,
telemetryRefreshRate, 'telemetry stats', undefined, 0, true
telemetryRefreshRate, undefined, 0, true
),
telemetryRefreshRate
);
Expand All @@ -139,7 +140,7 @@ export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {

// Post config data when the SDK is ready and if the telemetry submitter was started
if (submitter.isRunning()) {
const postMetricsConfigTask = submitterFactory(log, splitApi.postMetricsConfig, telemetryCacheConfigAdapter(telemetry, settings), 0, 'telemetry config', undefined, 0, true);
const postMetricsConfigTask = submitterFactory(log, splitApi.postMetricsConfig, telemetryCacheConfigAdapter(telemetry, settings), 0, undefined, 0, true);
postMetricsConfigTask.execute();
}
});
Expand Down
5 changes: 2 additions & 3 deletions src/sync/submitters/uniqueKeysSubmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
import { submitterFactory } from './submitter';

const DATA_NAME = 'unique keys';
const UNIQUE_KEYS_RATE = 900000; // 15 minutes

/**
Expand All @@ -19,12 +18,12 @@ export function uniqueKeysSubmitterFactory(params: ISdkFactoryContextSync) {
const isClientSide = key !== undefined;
const postUniqueKeysBulk = isClientSide ? postUniqueKeysBulkCs : postUniqueKeysBulkSs;

const syncTask = submitterFactory(log, postUniqueKeysBulk, uniqueKeys, UNIQUE_KEYS_RATE, DATA_NAME);
const syncTask = submitterFactory(log, postUniqueKeysBulk, uniqueKeys, UNIQUE_KEYS_RATE);

// register unique keys submitter to be executed when uniqueKeys cache is full
uniqueKeys.setOnFullQueueCb(() => {
if (syncTask.isRunning()) {
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [uniqueKeys.name]);
syncTask.execute();
}
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
Expand Down