@@ -75,6 +75,7 @@ export default class EppoClient {
75
75
private banditLogger ?: IBanditLogger ;
76
76
private isGracefulFailureMode = true ;
77
77
private assignmentCache ?: AssignmentCache ;
78
+ private banditAssignmentCache ?: AssignmentCache ;
78
79
private requestPoller ?: IPoller ;
79
80
private readonly evaluator = new Evaluator ( ) ;
80
81
private readonly banditEvaluator = new BanditEvaluator ( ) ;
@@ -651,6 +652,25 @@ export default class EppoClient {
651
652
}
652
653
653
654
private logBanditAction ( banditEvent : IBanditEvent ) : void {
655
+ const subjectKey = banditEvent . subject ;
656
+ const flagKey = banditEvent . featureFlag ;
657
+ const banditKey = banditEvent . bandit ;
658
+ const actionKey = banditEvent . action ?? '__eppo_no_action' ;
659
+
660
+ // What our bandit assignment cache cares about for avoiding logging duplicate bandit assignments,
661
+ // if one is active. Like the flag assignment cache, entries are only stored for a given flag
662
+ // and subject.
663
+ const banditAssignmentCacheProperties = {
664
+ flagKey,
665
+ subjectKey,
666
+ banditKey,
667
+ actionKey,
668
+ } ;
669
+
670
+ if ( this . banditAssignmentCache ?. has ( banditAssignmentCacheProperties ) ) {
671
+ return ;
672
+ }
673
+
654
674
if ( ! this . banditLogger ) {
655
675
// No bandit logger set; enqueue the event in case a logger is later set
656
676
if ( this . queuedBanditEvents . length < MAX_EVENT_QUEUE_SIZE ) {
@@ -661,6 +681,7 @@ export default class EppoClient {
661
681
// If here, we have a logger
662
682
try {
663
683
this . banditLogger . logBanditAction ( banditEvent ) ;
684
+ this . banditAssignmentCache ?. set ( banditAssignmentCacheProperties ) ;
664
685
} catch ( err ) {
665
686
logger . warn ( 'Error encountered logging bandit action' , err ) ;
666
687
}
@@ -904,6 +925,22 @@ export default class EppoClient {
904
925
this . assignmentCache = cache ;
905
926
}
906
927
928
+ public disableBanditAssignmentCache ( ) {
929
+ this . banditAssignmentCache = undefined ;
930
+ }
931
+
932
+ public useNonExpiringInMemoryBanditAssignmentCache ( ) {
933
+ this . banditAssignmentCache = new NonExpiringInMemoryAssignmentCache ( ) ;
934
+ }
935
+
936
+ public useLRUInMemoryBanditAssignmentCache ( maxSize : number ) {
937
+ this . banditAssignmentCache = new LRUInMemoryAssignmentCache ( maxSize ) ;
938
+ }
939
+
940
+ public useCustomBanditAssignmentCache ( cache : AssignmentCache ) {
941
+ this . banditAssignmentCache = cache ;
942
+ }
943
+
907
944
public setIsGracefulFailureMode ( gracefulFailureMode : boolean ) {
908
945
this . isGracefulFailureMode = gracefulFailureMode ;
909
946
}
0 commit comments