@eppo/js-client-sdk-common
Advanced tools
Comparing version 4.0.2 to 4.1.0
import { LRUCache } from './lru-cache'; | ||
export declare type AssignmentCacheValue = { | ||
allocationKey: string; | ||
variationKey: string; | ||
}; | ||
/** | ||
* Assignment cache keys are only on the subject and flag level, while the entire value is used | ||
* for uniqueness checking. This way that if an assigned variation or bandit action changes for a | ||
* flag, it evicts the old one. Then, if an older assignment is later reassigned, it will be treated | ||
* as new. | ||
*/ | ||
export declare type AssignmentCacheKey = { | ||
@@ -10,6 +12,15 @@ subjectKey: string; | ||
}; | ||
export declare type CacheKeyPair<T extends string, U extends string> = { | ||
[K in T]: string; | ||
} & { | ||
[K in U]: string; | ||
}; | ||
declare type VariationCacheValue = CacheKeyPair<'allocationKey', 'variationKey'>; | ||
declare type BanditCacheValue = CacheKeyPair<'banditKey', 'actionKey'>; | ||
export declare type AssignmentCacheValue = VariationCacheValue | BanditCacheValue; | ||
export declare type AssignmentCacheEntry = AssignmentCacheKey & AssignmentCacheValue; | ||
/** Converts an {@link AssignmentCacheKey} to a string. */ | ||
export declare function assignmentCacheKeyToString({ subjectKey, flagKey }: AssignmentCacheKey): string; | ||
export declare function assignmentCacheValueToString({ allocationKey, variationKey, }: AssignmentCacheValue): string; | ||
/** Converts an {@link AssignmentCacheValue} to a string. */ | ||
export declare function assignmentCacheValueToString(cacheValue: AssignmentCacheValue): string; | ||
export interface AsyncMap<K, V> { | ||
@@ -62,2 +73,3 @@ get(key: K): Promise<V | undefined>; | ||
} | ||
export {}; | ||
//# sourceMappingURL=abstract-assignment-cache.d.ts.map |
@@ -11,4 +11,5 @@ "use strict"; | ||
exports.assignmentCacheKeyToString = assignmentCacheKeyToString; | ||
function assignmentCacheValueToString({ allocationKey, variationKey, }) { | ||
return (0, obfuscation_1.getMD5Hash)([allocationKey, variationKey].join(';')); | ||
/** Converts an {@link AssignmentCacheValue} to a string. */ | ||
function assignmentCacheValueToString(cacheValue) { | ||
return (0, obfuscation_1.getMD5Hash)(Object.values(cacheValue).join(';')); | ||
} | ||
@@ -15,0 +16,0 @@ exports.assignmentCacheValueToString = assignmentCacheValueToString; |
@@ -39,2 +39,3 @@ import { IAssignmentLogger } from '../assignment-logger'; | ||
private assignmentCache?; | ||
private banditAssignmentCache?; | ||
private requestPoller?; | ||
@@ -202,2 +203,6 @@ private readonly evaluator; | ||
useCustomAssignmentCache(cache: AssignmentCache): void; | ||
disableBanditAssignmentCache(): void; | ||
useNonExpiringInMemoryBanditAssignmentCache(): void; | ||
useLRUInMemoryBanditAssignmentCache(maxSize: number): void; | ||
useCustomBanditAssignmentCache(cache: AssignmentCache): void; | ||
setIsGracefulFailureMode(gracefulFailureMode: boolean): void; | ||
@@ -204,0 +209,0 @@ getFlagConfigurations(): Record<string, Flag>; |
@@ -395,12 +395,29 @@ "use strict"; | ||
logBanditAction(banditEvent) { | ||
if (!this.banditLogger) { | ||
// No bandit logger set; enqueue the event in case a logger is later set | ||
if (this.queuedBanditEvents.length < constants_1.MAX_EVENT_QUEUE_SIZE) { | ||
this.queuedBanditEvents.push(banditEvent); | ||
} | ||
var _a, _b, _c; | ||
// First we check if this bandit action has been logged before | ||
const subjectKey = banditEvent.subject; | ||
const flagKey = banditEvent.featureFlag; | ||
const banditKey = banditEvent.bandit; | ||
const actionKey = (_a = banditEvent.action) !== null && _a !== void 0 ? _a : '__eppo_no_action'; | ||
const banditAssignmentCacheProperties = { | ||
flagKey, | ||
subjectKey, | ||
banditKey, | ||
actionKey, | ||
}; | ||
if ((_b = this.banditAssignmentCache) === null || _b === void 0 ? void 0 : _b.has(banditAssignmentCacheProperties)) { | ||
// Ignore repeat assignment | ||
return; | ||
} | ||
// If here, we have a logger | ||
// If here, we have a logger and a new assignment to be logged | ||
try { | ||
this.banditLogger.logBanditAction(banditEvent); | ||
if (this.banditLogger) { | ||
this.banditLogger.logBanditAction(banditEvent); | ||
} | ||
else if (this.queuedBanditEvents.length < constants_1.MAX_EVENT_QUEUE_SIZE) { | ||
// If no logger defined, queue up the events (up to a max) to flush if a logger is later defined | ||
this.queuedBanditEvents.push(banditEvent); | ||
} | ||
// Record in the assignment cache, if active, to deduplicate subsequent repeat assignments | ||
(_c = this.banditAssignmentCache) === null || _c === void 0 ? void 0 : _c.set(banditAssignmentCacheProperties); | ||
} | ||
@@ -583,2 +600,14 @@ catch (err) { | ||
} | ||
disableBanditAssignmentCache() { | ||
this.banditAssignmentCache = undefined; | ||
} | ||
useNonExpiringInMemoryBanditAssignmentCache() { | ||
this.banditAssignmentCache = new abstract_assignment_cache_1.NonExpiringInMemoryAssignmentCache(); | ||
} | ||
useLRUInMemoryBanditAssignmentCache(maxSize) { | ||
this.banditAssignmentCache = new abstract_assignment_cache_1.LRUInMemoryAssignmentCache(maxSize); | ||
} | ||
useCustomBanditAssignmentCache(cache) { | ||
this.banditAssignmentCache = cache; | ||
} | ||
setIsGracefulFailureMode(gracefulFailureMode) { | ||
@@ -620,10 +649,11 @@ this.isGracefulFailureMode = gracefulFailureMode; | ||
} | ||
// assignment logger may be null while waiting for initialization | ||
if (!this.assignmentLogger) { | ||
this.queuedAssignmentEvents.length < constants_1.MAX_EVENT_QUEUE_SIZE && | ||
try { | ||
if (this.assignmentLogger) { | ||
this.assignmentLogger.logAssignment(event); | ||
} | ||
else if (this.queuedAssignmentEvents.length < constants_1.MAX_EVENT_QUEUE_SIZE) { | ||
// assignment logger may be null while waiting for initialization, queue up events (up to a max) | ||
// to be flushed when set | ||
this.queuedAssignmentEvents.push(event); | ||
return; | ||
} | ||
try { | ||
this.assignmentLogger.logAssignment(event); | ||
} | ||
(_d = this.assignmentCache) === null || _d === void 0 ? void 0 : _d.set({ | ||
@@ -630,0 +660,0 @@ flagKey, |
{ | ||
"name": "@eppo/js-client-sdk-common", | ||
"version": "4.0.2", | ||
"version": "4.1.0", | ||
"description": "Eppo SDK for client-side JavaScript applications (base for both web and react native)", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -5,7 +5,8 @@ import { getMD5Hash } from '../obfuscation'; | ||
export type AssignmentCacheValue = { | ||
allocationKey: string; | ||
variationKey: string; | ||
}; | ||
/** | ||
* Assignment cache keys are only on the subject and flag level, while the entire value is used | ||
* for uniqueness checking. This way that if an assigned variation or bandit action changes for a | ||
* flag, it evicts the old one. Then, if an older assignment is later reassigned, it will be treated | ||
* as new. | ||
*/ | ||
export type AssignmentCacheKey = { | ||
@@ -16,2 +17,12 @@ subjectKey: string; | ||
export type CacheKeyPair<T extends string, U extends string> = { | ||
[K in T]: string; | ||
} & { | ||
[K in U]: string; | ||
}; | ||
type VariationCacheValue = CacheKeyPair<'allocationKey', 'variationKey'>; | ||
type BanditCacheValue = CacheKeyPair<'banditKey', 'actionKey'>; | ||
export type AssignmentCacheValue = VariationCacheValue | BanditCacheValue; | ||
export type AssignmentCacheEntry = AssignmentCacheKey & AssignmentCacheValue; | ||
@@ -24,7 +35,5 @@ | ||
export function assignmentCacheValueToString({ | ||
allocationKey, | ||
variationKey, | ||
}: AssignmentCacheValue): string { | ||
return getMD5Hash([allocationKey, variationKey].join(';')); | ||
/** Converts an {@link AssignmentCacheValue} to a string. */ | ||
export function assignmentCacheValueToString(cacheValue: AssignmentCacheValue): string { | ||
return getMD5Hash(Object.values(cacheValue).join(';')); | ||
} | ||
@@ -31,0 +40,0 @@ |
@@ -78,2 +78,3 @@ import ApiEndpoints from '../api-endpoints'; | ||
private assignmentCache?: AssignmentCache; | ||
private banditAssignmentCache?: AssignmentCache; | ||
private requestPoller?: IPoller; | ||
@@ -655,12 +656,30 @@ private readonly evaluator = new Evaluator(); | ||
private logBanditAction(banditEvent: IBanditEvent): void { | ||
if (!this.banditLogger) { | ||
// No bandit logger set; enqueue the event in case a logger is later set | ||
if (this.queuedBanditEvents.length < MAX_EVENT_QUEUE_SIZE) { | ||
this.queuedBanditEvents.push(banditEvent); | ||
} | ||
// First we check if this bandit action has been logged before | ||
const subjectKey = banditEvent.subject; | ||
const flagKey = banditEvent.featureFlag; | ||
const banditKey = banditEvent.bandit; | ||
const actionKey = banditEvent.action ?? '__eppo_no_action'; | ||
const banditAssignmentCacheProperties = { | ||
flagKey, | ||
subjectKey, | ||
banditKey, | ||
actionKey, | ||
}; | ||
if (this.banditAssignmentCache?.has(banditAssignmentCacheProperties)) { | ||
// Ignore repeat assignment | ||
return; | ||
} | ||
// If here, we have a logger | ||
// If here, we have a logger and a new assignment to be logged | ||
try { | ||
this.banditLogger.logBanditAction(banditEvent); | ||
if (this.banditLogger) { | ||
this.banditLogger.logBanditAction(banditEvent); | ||
} else if (this.queuedBanditEvents.length < MAX_EVENT_QUEUE_SIZE) { | ||
// If no logger defined, queue up the events (up to a max) to flush if a logger is later defined | ||
this.queuedBanditEvents.push(banditEvent); | ||
} | ||
// Record in the assignment cache, if active, to deduplicate subsequent repeat assignments | ||
this.banditAssignmentCache?.set(banditAssignmentCacheProperties); | ||
} catch (err) { | ||
@@ -909,2 +928,18 @@ logger.warn('Error encountered logging bandit action', err); | ||
public disableBanditAssignmentCache() { | ||
this.banditAssignmentCache = undefined; | ||
} | ||
public useNonExpiringInMemoryBanditAssignmentCache() { | ||
this.banditAssignmentCache = new NonExpiringInMemoryAssignmentCache(); | ||
} | ||
public useLRUInMemoryBanditAssignmentCache(maxSize: number) { | ||
this.banditAssignmentCache = new LRUInMemoryAssignmentCache(maxSize); | ||
} | ||
public useCustomBanditAssignmentCache(cache: AssignmentCache) { | ||
this.banditAssignmentCache = cache; | ||
} | ||
public setIsGracefulFailureMode(gracefulFailureMode: boolean) { | ||
@@ -962,10 +997,10 @@ this.isGracefulFailureMode = gracefulFailureMode; | ||
// assignment logger may be null while waiting for initialization | ||
if (!this.assignmentLogger) { | ||
this.queuedAssignmentEvents.length < MAX_EVENT_QUEUE_SIZE && | ||
try { | ||
if (this.assignmentLogger) { | ||
this.assignmentLogger.logAssignment(event); | ||
} else if (this.queuedAssignmentEvents.length < MAX_EVENT_QUEUE_SIZE) { | ||
// assignment logger may be null while waiting for initialization, queue up events (up to a max) | ||
// to be flushed when set | ||
this.queuedAssignmentEvents.push(event); | ||
return; | ||
} | ||
try { | ||
this.assignmentLogger.logAssignment(event); | ||
} | ||
this.assignmentCache?.set({ | ||
@@ -972,0 +1007,0 @@ flagKey, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
810460
6612